Skip to content

sonolus.script.archetype

ArchetypeLife

Bases: Record

How an entity contributes to life.

good_increment instance-attribute

Life increment for a good judgment.

great_increment instance-attribute

Life increment for a great judgment.

miss_increment instance-attribute

Life increment for a miss judgment.

perfect_increment instance-attribute

Life increment for a perfect judgment.

__pos__()

Return a copy of the record.

type_var_value(var) classmethod

Return the value of a type variable.

Parameters:

Name Type Description Default
var TypeVar

The type variable to get the value of.

required

Returns:

Type Description
Any

The value of the type variable.

update(perfect_increment=None, great_increment=None, good_increment=None, miss_increment=None)

Update the life increments.

EntityRef

Bases: Record

Reference to another entity.

May be used with Any to reference an unknown archetype.

Usage
class MyArchetype(PlayArchetype):
    ref_1: EntityRef[OtherArchetype] = imported()
    ref_2: EntityRef[Any] = imported()

__pos__()

Return a copy of the record.

archetype() classmethod

Get the archetype type.

archetype_matches()

Check if entity at the index is precisely of the archetype.

get()

Get the entity.

type_var_value(var) classmethod

Return the value of a type variable.

Parameters:

Name Type Description Default
var TypeVar

The type variable to get the value of.

required

Returns:

Type Description
Any

The value of the type variable.

with_archetype(archetype)

Return a new reference with the given archetype type.

PlayArchetype

Bases: _BaseArchetype

Base class for play mode archetypes.

Usage
class MyArchetype(PlayArchetype):
    # Set to True if the entity is a note and contributes to combo and score
    # Default is False
    is_scored: bool = True

    imported_field: int = imported()
    exported_field: int = exported()
    entity_memory_field: int = entity_memory()
    shared_memory_field: int = shared_memory()

    @callback(order=1)
    def preprocess(self):
        ...

despawn property writable

Whether the entity should be despawned after this frame.

Setting this to True will despawn the entity.

index property

The index of this entity.

is_active property

Whether this entity is active.

is_despawned property

Whether this entity is despawned.

is_scored = False class-attribute

Whether the entity contributes to combo and score.

is_waiting property

Whether this entity is waiting to be spawned.

life property

How this entity contributes to life.

name = None class-attribute

The name of the archetype.

If not set, the name will be the class name.

The name is used in level data.

result property

The result of this entity.

Only meaningful for scored entities.

initialize()

Initialize this entity.

Runs when this entity is spawned.

preprocess()

Perform upfront processing.

Runs first when the level is loaded.

ref()

Get a reference to this entity.

Valid both in level data and in callbacks.

should_spawn()

Return whether the entity should be spawned.

Runs each frame while the entity is the first entity in the spawn queue.

spawn(**kwargs) classmethod

Spawn an entity of this archetype, injecting the given values into entity memory.

Usage
class MyArchetype(PlayArchetype):
    field: int = entity_memory()

def f():
    MyArchetype.spawn(field=123)

Parameters:

Name Type Description Default
**kwargs Any

Entity memory values to inject by field name as defined in the Archetype.

{}

spawn_order()

Return the spawn order of the entity.

Runs when the level is loaded after preprocess.

terminate()

Finalize before despawning.

Runs when the entity is despawned.

touch()

Handle user input.

Runs after update_sequential each frame.

update_parallel()

Perform parallel actions for this frame.

Runs after touch each frame.

This is where most gameplay logic should be placed.

update_sequential()

Perform non-parallel actions for this frame.

Runs first each frame.

This is where logic affecting shared memory should be placed. Other logic should be placed in update_parallel for better performance.

PreviewArchetype

Bases: _BaseArchetype

Base class for preview mode archetypes.

Usage
class MyArchetype(PreviewArchetype):
    imported_field: int = imported()
    entity_memory_field: int = entity_memory()
    shared_memory_field: int = shared_memory()

    @callback(order=1)
    def preprocess(self):
        ...

index property

The index of this entity.

name = None class-attribute

The name of the archetype.

If not set, the name will be the class name.

The name is used in level data.

preprocess()

Perform upfront processing.

Runs first when the level is loaded.

ref()

Get a reference to this entity.

Valid both in level data and in callbacks.

render()

Render the entity.

Runs after preprocess.

spawn(**kwargs) classmethod

Spawn an entity of this archetype, injecting the given values into entity memory.

Usage
class MyArchetype(PlayArchetype):
    field: int = entity_memory()

def f():
    MyArchetype.spawn(field=123)

Parameters:

Name Type Description Default
**kwargs Any

Entity memory values to inject by field name as defined in the Archetype.

{}

StandardArchetypeName

Bases: StrEnum

Standard archetype names.

BPM_CHANGE = '#BPM_CHANGE' class-attribute instance-attribute

Bpm change marker

TIMESCALE_CHANGE = '#TIMESCALE_CHANGE' class-attribute instance-attribute

Timescale change marker

StandardImport

Standard import annotations for Archetype fields.

Usage
class MyArchetype(WatchArchetype):
    judgment: StandardImport.JUDGMENT

ACCURACY = Annotated[float, imported(name='#ACCURACY')] class-attribute instance-attribute

The accuracy of the entity.

Automatically supported in watch mode for archetypes with a corresponding scored play mode archetype.

BEAT = Annotated[float, imported(name='#BEAT')] class-attribute instance-attribute

The beat of the entity.

BPM = Annotated[float, imported(name='#BPM')] class-attribute instance-attribute

The bpm, for bpm change markers.

JUDGMENT = Annotated[int, imported(name='#JUDGMENT')] class-attribute instance-attribute

The judgment of the entity.

Automatically supported in watch mode for archetypes with a corresponding scored play mode archetype.

TIMESCALE = Annotated[float, imported(name='#TIMESCALE')] class-attribute instance-attribute

The timescale, for timescale change markers.

WatchArchetype

Bases: _BaseArchetype

Base class for watch mode archetypes.

Usage
class MyArchetype(WatchArchetype):
    imported_field: int = imported()
    entity_memory_field: int = entity_memory()
    shared_memory_field: int = shared_memory()

    @callback(order=1)
    def update_sequential(self):
        ...

index property

The index of this entity.

is_active property

Whether this entity is active.

life property

How this entity contributes to life.

name = None class-attribute

The name of the archetype.

If not set, the name will be the class name.

The name is used in level data.

result property

The result of this entity.

Only meaningful for scored entities.

despawn_time()

Return the despawn time of the entity.

initialize()

Initialize this entity.

Runs when this entity is spawned.

preprocess()

Perform upfront processing.

Runs first when the level is loaded.

ref()

Get a reference to this entity.

Valid both in level data and in callbacks.

spawn(**kwargs) classmethod

Spawn an entity of this archetype, injecting the given values into entity memory.

Usage
class MyArchetype(PlayArchetype):
    field: int = entity_memory()

def f():
    MyArchetype.spawn(field=123)

Parameters:

Name Type Description Default
**kwargs Any

Entity memory values to inject by field name as defined in the Archetype.

{}

spawn_time()

Return the spawn time of the entity.

terminate()

Finalize before despawning.

Runs when the entity is despawned.

update_parallel()

Parallel update callback.

Runs after touch each frame.

This is where most gameplay logic should be placed.

update_sequential()

Perform non-parallel actions for this frame.

Runs first each frame.

This is where logic affecting shared memory should be placed. Other logic should be placed in update_parallel for better performance.

archetype_life_of(archetype)

Retrieve the archetype life of the given archetype.

Available in play and watch mode.

callback(*, order=0)

Annotate a callback with its order.

Callbacks are execute from lowest to highest order. By default, callbacks have an order of 0.

Usage
class MyArchetype(PlayArchetype):
    @callback(order=1)
    def update_sequential(self):
        pass

Parameters:

Name Type Description Default
order int

The order of the callback. Lower values are executed first.

0

entity_data()

Declare a field as entity data.

Entity data is accessible from other entities, but may only be updated in the preprocess callback and is read-only in other callbacks.

It functions like imported and shares the same underlying storage, except that it is not loaded from a level.

Usage
class MyArchetype(PlayArchetype):
    field: int = entity_data()

entity_info_at(index)

Retrieve entity info of the entity at the given index.

Available in play, watch, and preview mode.

entity_memory()

Declare a field as entity memory.

Entity memory is private to the entity and is not accessible from other entities. It may be read or updated in any callback associated with the entity.

Entity memory fields may also be set when an entity is spawned using the spawn() method.

Usage
class MyArchetype(PlayArchetype):
    field: int = entity_memory()

exported(*, name=None)

Declare a field as exported.

This is only usable in play mode to export data to be loaded in watch mode.

Exported fields are write-only.

Usage
class MyArchetype(PlayArchetype):
    field: int = exported()
    field_with_explicit_name: int = exported(name="#FIELD")

imported(*, name=None)

Declare a field as imported.

Imported fields may be loaded from the level.

In watch mode, data may also be loaded from a corresponding exported field in play mode.

Imported fields may only be updated in the preprocess callback, and are read-only in other callbacks.

Usage
class MyArchetype(PlayArchetype):
    field: int = imported()
    field_with_explicit_name: int = imported(name="field_name")

shared_memory()

Declare a field as shared memory.

Shared memory is accessible from other entities.

Shared memory may be read in any callback, but may only be updated by sequential callbacks (preprocess, update_sequential, and touch).

Usage
class MyArchetype(PlayArchetype):
    field: int = shared_memory()