From 4c5a31d34bcbfdf91e11258ac843bec920ab6bc5 Mon Sep 17 00:00:00 2001 From: Michele Peruzzi Date: Wed, 10 Dec 2025 10:42:08 +0100 Subject: [PATCH 01/12] initial draft --- .../core-tech/proposals/proposal.md | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/en/space-station-14/core-tech/proposals/proposal.md diff --git a/src/en/space-station-14/core-tech/proposals/proposal.md b/src/en/space-station-14/core-tech/proposals/proposal.md new file mode 100644 index 0000000000..19fb35dd2e --- /dev/null +++ b/src/en/space-station-14/core-tech/proposals/proposal.md @@ -0,0 +1,74 @@ +# Animation State Machine System + +| Designers | Coders | Implemented | GitHub Links | +|---|---|---|---| +| Ataman | Ataman | :x: No | TBD | + +## Overview +This is a proposal to add an animation state machine (ASM) system which can be used to implement all kinds of temporary or persistant animations to entities like blinking eyes and waddling. The system offers a framework consisting of timers, triggers and conditions that can be defined in YAML to run these animations at the appropriate times. + +## Background +Thinks like blinking eyes and clown shoe waddling has been implemented in the past by creating whole specialized systems for their sole task of running very simple animations under certain conditions. In almost every PR for these, one can find comments wishing for a more generalized animation system that could be used instead. + +## Features to be added +### Animation State Machine +The ASM consists of a system and components (running client side as much as possible) to trigger animations under certain conditions all defined in YAML. Since an entity might need to run multiple animations simultaneously, the component consists of a list of ASMs to run in parallel. + +### Animation States +Added to a ASM's list of possible animations including their conditions, animation to play, etc. Each state defines exactly one animation to run after entering. + +### Conditions, Triggers and Timers +In order to define when these animations are supposed to run, we require hardcoded types for use in YAML. Incomplete examples list: + +#### Conditions +These are checked and must return true for the specified animation state to run. +- ```HasComponents```: Is true if the entity contains all specified components. (Example: Coughing requiring a ```LungComponent```). +- ```MatchComponentPropertyValue```: Is true if the given component and datafield exists on an entity and has the specified value. (Example: Blinking requiring the ```MobStateComponent``` with ```CurrentState``` being ```MobState.Alive```.) + +#### Triggers +Used to trigger state condition checks, examples: +- A wrapper around ```SubscribeLocalEvent()``` used for reacting to arbitrary events. +- ```ComponentAdded```/```ComponentRemoved``` is obvious. + +There is also an implicit trigger being run when entities become part of the client's rendering area. + +The main reason for triggers is to keep the performance impact in check. Testing dozens of conditions of several entities every frame would certainly leave a mark. + +#### Timers +Some animations might want to be played in fixed or random intervals. +- ```RandomTimeRangeTimer```: Fires at random intervals inside a defined range. (Examples: Blinking, Coughing) +- ```TimeIntervalTimer```: Fires at fixed intervals. (Example: Blinking indicator light) + +## Game Design Rationale +Animations can be useful in adding flavor and immersion to the game in many ways, the above mentioned examples just being a few. They add can add immersion for everybody, even the smallest mice. However, animations are currently difficult to implement properly and require not only coding knowledge for the animation itself but for the system running said animation in the first place as well. + +## Roundflow & Player interaction +Considering this is a background system it does not affect roundflow and never requires a player to interact with it intentionally. + +## Administrative & Server Rule Impact (if applicable) +N/A + +# Technical Considerations +## General +Ideally, the whole system runs client side only. To account for triggers that depend on events which might happen outside a players rendering view; all state conditions are tested once an entity comes into view. If this should impact performance, a flag will be added to disable this trigger for animations where it's irrelevant. + +Performance impact heavily depends on how the concrete states will be implemented. Defining a handful of timers running at 0.1s seconds interval with badly chosen conditions could have a very noticeable performance impact. This issue can be migitated by implementing a hard coded minimum interval however. + +This proposal ignores multi-state machines in favor of not adding even more complexity to an already complex implementation. + +## Animations don't support YAML +While YAML defineable animations would be preferable. This should doable using hardcoded animations. If animations ever start supporting YAML, this system can easily be upgraded to use those instead. + +## SpriteComponent changes/refactor, yes or no? +While a refactor of SpriteComponent has some advantages like not adding another system and automatically upgrading all sprites with ASM availability; this proposal is using an independent system due to the following reasons: +- The ASM could be used for more than sprites, i.e.: sound cues for coughing. +- An independent system can be added and removed more easily from the engine. +- The component can be isolated to those entities that need it. (A piece of paper probably doesn't need animations). + +## New Types +- ```AnimationStateMachineComponent``` Component for holding all state machines of an entity and their state. +- ```AnimationStateMachineSystem``` Client-side only system running the ASM's of all entities inside the players rendering view. +- ```AnimationStateMachineState``` Abstract base type for ASM states. +- ```AnimationStateMachineTrigger``` Abstract base type for triggers. +- ```AnimationStateMachineTimer``` Abstract base type for timers. +- ```AnimationStateMachineCondition``` Abstract base type for conditions. From 2f82aa1994e36bb453ed485788cfc4cdbd0e80a1 Mon Sep 17 00:00:00 2001 From: Michele Peruzzi Date: Wed, 10 Dec 2025 10:44:01 +0100 Subject: [PATCH 02/12] typo --- src/en/space-station-14/core-tech/proposals/proposal.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/en/space-station-14/core-tech/proposals/proposal.md b/src/en/space-station-14/core-tech/proposals/proposal.md index 19fb35dd2e..a38835db89 100644 --- a/src/en/space-station-14/core-tech/proposals/proposal.md +++ b/src/en/space-station-14/core-tech/proposals/proposal.md @@ -8,7 +8,7 @@ This is a proposal to add an animation state machine (ASM) system which can be used to implement all kinds of temporary or persistant animations to entities like blinking eyes and waddling. The system offers a framework consisting of timers, triggers and conditions that can be defined in YAML to run these animations at the appropriate times. ## Background -Thinks like blinking eyes and clown shoe waddling has been implemented in the past by creating whole specialized systems for their sole task of running very simple animations under certain conditions. In almost every PR for these, one can find comments wishing for a more generalized animation system that could be used instead. +Things like blinking eyes and clown shoe waddling has been implemented in the past by creating whole specialized systems for their sole task of running very simple animations under certain conditions. In almost every PR for these, one can find comments wishing for a more generalized animation system that could be used instead. ## Features to be added ### Animation State Machine From 1a34fbf8c8cd3b134ddd54c96845092088255762 Mon Sep 17 00:00:00 2001 From: j-orgy <85228883+j-orgy@users.noreply.github.com> Date: Wed, 10 Dec 2025 11:54:59 +0100 Subject: [PATCH 03/12] Update proposal.md proofread pt 1 --- .../core-tech/proposals/proposal.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/en/space-station-14/core-tech/proposals/proposal.md b/src/en/space-station-14/core-tech/proposals/proposal.md index a38835db89..b755783c9e 100644 --- a/src/en/space-station-14/core-tech/proposals/proposal.md +++ b/src/en/space-station-14/core-tech/proposals/proposal.md @@ -5,10 +5,10 @@ | Ataman | Ataman | :x: No | TBD | ## Overview -This is a proposal to add an animation state machine (ASM) system which can be used to implement all kinds of temporary or persistant animations to entities like blinking eyes and waddling. The system offers a framework consisting of timers, triggers and conditions that can be defined in YAML to run these animations at the appropriate times. +This is a proposal to add an animation state machine (ASM) system which can be used to implement all kinds of temporary or persistant animations to entities like blinking eyes and waddling. The system would offer a framework consisting of timers, triggers and conditions that can be defined in YAML to run these animations at the appropriate times. ## Background -Things like blinking eyes and clown shoe waddling has been implemented in the past by creating whole specialized systems for their sole task of running very simple animations under certain conditions. In almost every PR for these, one can find comments wishing for a more generalized animation system that could be used instead. +Things like blinking eyes and clown shoe waddling have been implemented in the past by creating whole specialized systems for their sole task of running very simple animations under certain conditions. In almost every PR for these, one can find comments wishing for a more generalized animation system that could be used instead. ## Features to be added ### Animation State Machine @@ -18,7 +18,7 @@ The ASM consists of a system and components (running client side as much as poss Added to a ASM's list of possible animations including their conditions, animation to play, etc. Each state defines exactly one animation to run after entering. ### Conditions, Triggers and Timers -In order to define when these animations are supposed to run, we require hardcoded types for use in YAML. Incomplete examples list: +In order to define when these animations are supposed to run, we require hardcoded types for use in YAML. Some examples include: #### Conditions These are checked and must return true for the specified animation state to run. @@ -26,31 +26,31 @@ These are checked and must return true for the specified animation state to run. - ```MatchComponentPropertyValue```: Is true if the given component and datafield exists on an entity and has the specified value. (Example: Blinking requiring the ```MobStateComponent``` with ```CurrentState``` being ```MobState.Alive```.) #### Triggers -Used to trigger state condition checks, examples: +Used to trigger state condition checks, for example: - A wrapper around ```SubscribeLocalEvent()``` used for reacting to arbitrary events. -- ```ComponentAdded```/```ComponentRemoved``` is obvious. +- ```ComponentAdded```/```ComponentRemoved```. -There is also an implicit trigger being run when entities become part of the client's rendering area. +An implicit trigger is also executed when entities enter the client's rendering area. -The main reason for triggers is to keep the performance impact in check. Testing dozens of conditions of several entities every frame would certainly leave a mark. +The main reason for triggers minimize performance impact. Testing many conditions of several entities every frame would have a large impact on performance. #### Timers -Some animations might want to be played in fixed or random intervals. +Allow animations to be played at fixed or random intervals - ```RandomTimeRangeTimer```: Fires at random intervals inside a defined range. (Examples: Blinking, Coughing) - ```TimeIntervalTimer```: Fires at fixed intervals. (Example: Blinking indicator light) ## Game Design Rationale -Animations can be useful in adding flavor and immersion to the game in many ways, the above mentioned examples just being a few. They add can add immersion for everybody, even the smallest mice. However, animations are currently difficult to implement properly and require not only coding knowledge for the animation itself but for the system running said animation in the first place as well. +Animations are great for adding flavor and immersion to the game in many ways, the above mentioned examples just being a few. They add immersion for everybody, even the smallest mice. However, animations are currently difficult to implement properly and require not only coding knowledge for the animation itself but for the system running said animation in the first place as well. ## Roundflow & Player interaction -Considering this is a background system it does not affect roundflow and never requires a player to interact with it intentionally. +This is a background system, it does not affect roundflow and never requires a player to interact with it. ## Administrative & Server Rule Impact (if applicable) N/A # Technical Considerations ## General -Ideally, the whole system runs client side only. To account for triggers that depend on events which might happen outside a players rendering view; all state conditions are tested once an entity comes into view. If this should impact performance, a flag will be added to disable this trigger for animations where it's irrelevant. +Ideally, the whole system should run client side. To account for triggers that depend on events which happen outside a player's rendering view; all state conditions are tested once an entity comes into view. If this should impact performance, a flag will be added to disable this trigger for animations where it's irrelevant. Performance impact heavily depends on how the concrete states will be implemented. Defining a handful of timers running at 0.1s seconds interval with badly chosen conditions could have a very noticeable performance impact. This issue can be migitated by implementing a hard coded minimum interval however. From 3318cade52b47c624c9c3411db15ef222d71f77c Mon Sep 17 00:00:00 2001 From: j-orgy <85228883+j-orgy@users.noreply.github.com> Date: Wed, 10 Dec 2025 12:09:28 +0100 Subject: [PATCH 04/12] Update proposal.md proofread pt 1 --- .../space-station-14/core-tech/proposals/proposal.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/en/space-station-14/core-tech/proposals/proposal.md b/src/en/space-station-14/core-tech/proposals/proposal.md index b755783c9e..8c111ac7d0 100644 --- a/src/en/space-station-14/core-tech/proposals/proposal.md +++ b/src/en/space-station-14/core-tech/proposals/proposal.md @@ -14,8 +14,7 @@ Things like blinking eyes and clown shoe waddling have been implemented in the p ### Animation State Machine The ASM consists of a system and components (running client side as much as possible) to trigger animations under certain conditions all defined in YAML. Since an entity might need to run multiple animations simultaneously, the component consists of a list of ASMs to run in parallel. -### Animation States -Added to a ASM's list of possible animations including their conditions, animation to play, etc. Each state defines exactly one animation to run after entering. +Each ASM state consists of conditions, triggers and timers resulting in the execution of a singular animation. ### Conditions, Triggers and Timers In order to define when these animations are supposed to run, we require hardcoded types for use in YAML. Some examples include: @@ -52,12 +51,12 @@ N/A ## General Ideally, the whole system should run client side. To account for triggers that depend on events which happen outside a player's rendering view; all state conditions are tested once an entity comes into view. If this should impact performance, a flag will be added to disable this trigger for animations where it's irrelevant. -Performance impact heavily depends on how the concrete states will be implemented. Defining a handful of timers running at 0.1s seconds interval with badly chosen conditions could have a very noticeable performance impact. This issue can be migitated by implementing a hard coded minimum interval however. +Performance impact heavily depends on how the concrete states will be implemented. Defining a handful of timers running at 0.1s seconds interval with badly chosen conditions could have a noticeable performance impact. This issue can be migitated by implementing a hard coded minimum interval however. This proposal ignores multi-state machines in favor of not adding even more complexity to an already complex implementation. ## Animations don't support YAML -While YAML defineable animations would be preferable. This should doable using hardcoded animations. If animations ever start supporting YAML, this system can easily be upgraded to use those instead. +While YAML defineable animations would be preferable, this should be doable using hardcoded animations. If animations ever support YAML, this system can easily be updated to use those instead. ## SpriteComponent changes/refactor, yes or no? While a refactor of SpriteComponent has some advantages like not adding another system and automatically upgrading all sprites with ASM availability; this proposal is using an independent system due to the following reasons: @@ -66,8 +65,8 @@ While a refactor of SpriteComponent has some advantages like not adding another - The component can be isolated to those entities that need it. (A piece of paper probably doesn't need animations). ## New Types -- ```AnimationStateMachineComponent``` Component for holding all state machines of an entity and their state. -- ```AnimationStateMachineSystem``` Client-side only system running the ASM's of all entities inside the players rendering view. +- ```AnimationStateMachineComponent``` Component to hold all state machines of an entity and their state. +- ```AnimationStateMachineSystem``` Client-side only system to execute the ASM's of all entities inside the players rendering view. - ```AnimationStateMachineState``` Abstract base type for ASM states. - ```AnimationStateMachineTrigger``` Abstract base type for triggers. - ```AnimationStateMachineTimer``` Abstract base type for timers. From b7a0200796c1d3f560b5cc34f0915b9c9e71852e Mon Sep 17 00:00:00 2001 From: j-orgy <85228883+j-orgy@users.noreply.github.com> Date: Thu, 11 Dec 2025 16:16:48 +0100 Subject: [PATCH 05/12] Gen. readability and grammar --- .../core-tech/proposals/proposal.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/en/space-station-14/core-tech/proposals/proposal.md b/src/en/space-station-14/core-tech/proposals/proposal.md index 8c111ac7d0..5ec3e2bc85 100644 --- a/src/en/space-station-14/core-tech/proposals/proposal.md +++ b/src/en/space-station-14/core-tech/proposals/proposal.md @@ -14,32 +14,32 @@ Things like blinking eyes and clown shoe waddling have been implemented in the p ### Animation State Machine The ASM consists of a system and components (running client side as much as possible) to trigger animations under certain conditions all defined in YAML. Since an entity might need to run multiple animations simultaneously, the component consists of a list of ASMs to run in parallel. -Each ASM state consists of conditions, triggers and timers resulting in the execution of a singular animation. +Each ASM state consists of conditions, triggers and/or timers resulting in the execution of a singular animation. ### Conditions, Triggers and Timers -In order to define when these animations are supposed to run, we require hardcoded types for use in YAML. Some examples include: +In order to define when these animations are supposed to run, we require hardcoded types for use in YAML, for example: #### Conditions These are checked and must return true for the specified animation state to run. -- ```HasComponents```: Is true if the entity contains all specified components. (Example: Coughing requiring a ```LungComponent```). -- ```MatchComponentPropertyValue```: Is true if the given component and datafield exists on an entity and has the specified value. (Example: Blinking requiring the ```MobStateComponent``` with ```CurrentState``` being ```MobState.Alive```.) +- ```HasComponents```: Is true if the entity contains all specified components. (For example: Coughing requiring a ```LungComponent```). +- ```MatchComponentPropertyValue```: Is true if the given component and datafield exists on an entity and has the specified value. (For example: Blinking requiring the ```MobStateComponent``` with ```CurrentState``` being ```MobState.Alive```.) #### Triggers Used to trigger state condition checks, for example: - A wrapper around ```SubscribeLocalEvent()``` used for reacting to arbitrary events. -- ```ComponentAdded```/```ComponentRemoved```. +- ```ComponentAdded```/```ComponentRemoved``` An implicit trigger is also executed when entities enter the client's rendering area. -The main reason for triggers minimize performance impact. Testing many conditions of several entities every frame would have a large impact on performance. +The main reason for triggers is to minimize performance impact, as testing many conditions of several entities every frame could have a large impact on performance. #### Timers Allow animations to be played at fixed or random intervals -- ```RandomTimeRangeTimer```: Fires at random intervals inside a defined range. (Examples: Blinking, Coughing) -- ```TimeIntervalTimer```: Fires at fixed intervals. (Example: Blinking indicator light) +- ```RandomTimeRangeTimer```: Fires at random intervals inside a defined range. (For example: Blinking, Coughing) +- ```TimeIntervalTimer```: Fires at fixed intervals. (For example: Blinking indicator light) ## Game Design Rationale -Animations are great for adding flavor and immersion to the game in many ways, the above mentioned examples just being a few. They add immersion for everybody, even the smallest mice. However, animations are currently difficult to implement properly and require not only coding knowledge for the animation itself but for the system running said animation in the first place as well. +Animations are great for adding flavor and immersion to the game in many ways, the above mentioned examples just being a few. However, animations are currently difficult to implement correctly and require coding knowledge of animations as well as the system running said animations. The new system would be much easier to use, especially once YAML support for animations is implemented. ## Roundflow & Player interaction This is a background system, it does not affect roundflow and never requires a player to interact with it. @@ -51,9 +51,9 @@ N/A ## General Ideally, the whole system should run client side. To account for triggers that depend on events which happen outside a player's rendering view; all state conditions are tested once an entity comes into view. If this should impact performance, a flag will be added to disable this trigger for animations where it's irrelevant. -Performance impact heavily depends on how the concrete states will be implemented. Defining a handful of timers running at 0.1s seconds interval with badly chosen conditions could have a noticeable performance impact. This issue can be migitated by implementing a hard coded minimum interval however. +Performance impact will heavily depend on how states are implemented. Many timers running at short intervals with subpar conditions could have a noticable performance impact - this can be mitigated through hard coded minimum intervals. -This proposal ignores multi-state machines in favor of not adding even more complexity to an already complex implementation. +This proposal ignores multi-state machines in favor of not adding more complexity to an already complex implementation. ## Animations don't support YAML While YAML defineable animations would be preferable, this should be doable using hardcoded animations. If animations ever support YAML, this system can easily be updated to use those instead. @@ -62,10 +62,10 @@ While YAML defineable animations would be preferable, this should be doable usin While a refactor of SpriteComponent has some advantages like not adding another system and automatically upgrading all sprites with ASM availability; this proposal is using an independent system due to the following reasons: - The ASM could be used for more than sprites, i.e.: sound cues for coughing. - An independent system can be added and removed more easily from the engine. -- The component can be isolated to those entities that need it. (A piece of paper probably doesn't need animations). +- The ASM component can be isolated to those entities that need it. (A piece of paper probably doesn't need animations). ## New Types -- ```AnimationStateMachineComponent``` Component to hold all state machines of an entity and their state. +- ```AnimationStateMachineComponent``` Component to hold all state machines of an entity and their states. - ```AnimationStateMachineSystem``` Client-side only system to execute the ASM's of all entities inside the players rendering view. - ```AnimationStateMachineState``` Abstract base type for ASM states. - ```AnimationStateMachineTrigger``` Abstract base type for triggers. From 5ef64dc5c43e2199c6fadb782f368b9d2e3a2a4d Mon Sep 17 00:00:00 2001 From: j-orgy <85228883+j-orgy@users.noreply.github.com> Date: Thu, 11 Dec 2025 16:49:11 +0100 Subject: [PATCH 06/12] updated to havve more consistent use of future tense where applicable, proposal is for a system which does not yet exist and now reflects that better --- .../core-tech/proposals/proposal.md | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/en/space-station-14/core-tech/proposals/proposal.md b/src/en/space-station-14/core-tech/proposals/proposal.md index 5ec3e2bc85..59bad84a91 100644 --- a/src/en/space-station-14/core-tech/proposals/proposal.md +++ b/src/en/space-station-14/core-tech/proposals/proposal.md @@ -5,51 +5,53 @@ | Ataman | Ataman | :x: No | TBD | ## Overview -This is a proposal to add an animation state machine (ASM) system which can be used to implement all kinds of temporary or persistant animations to entities like blinking eyes and waddling. The system would offer a framework consisting of timers, triggers and conditions that can be defined in YAML to run these animations at the appropriate times. +This is a proposal to add an animation state machine (ASM) system that can be used to implement all kinds of temporary or persistent animations to entities like blinking eyes and waddling. The system would offer a framework consisting of timers, triggers, and conditions that can be defined in YAML to run these animations at the appropriate times. ## Background -Things like blinking eyes and clown shoe waddling have been implemented in the past by creating whole specialized systems for their sole task of running very simple animations under certain conditions. In almost every PR for these, one can find comments wishing for a more generalized animation system that could be used instead. +Things like blinking eyes and clown shoe waddling have been implemented in the past by creating specialized systems for their sole task of running simple animations under certain conditions. In almost every PR for these, one can find comments wishing for a more generalized animation system that could be used instead. ## Features to be added ### Animation State Machine -The ASM consists of a system and components (running client side as much as possible) to trigger animations under certain conditions all defined in YAML. Since an entity might need to run multiple animations simultaneously, the component consists of a list of ASMs to run in parallel. +The ASM will consist of a system and components (primarily client-side) to trigger animations under certain conditions, all defined in YAML. Since an entity might need to run multiple animations simultaneously, the component will consist of a list of ASMs to run in parallel. -Each ASM state consists of conditions, triggers and/or timers resulting in the execution of a singular animation. +Each ASM state will contain conditions, triggers and/or timers resulting in the execution of a single animation. -### Conditions, Triggers and Timers -In order to define when these animations are supposed to run, we require hardcoded types for use in YAML, for example: +### Conditions, Triggers, and Timers +In order to define when these animations are supposed to run, hardcoded types for use in YAML are required, for example: #### Conditions -These are checked and must return true for the specified animation state to run. -- ```HasComponents```: Is true if the entity contains all specified components. (For example: Coughing requiring a ```LungComponent```). -- ```MatchComponentPropertyValue```: Is true if the given component and datafield exists on an entity and has the specified value. (For example: Blinking requiring the ```MobStateComponent``` with ```CurrentState``` being ```MobState.Alive```.) +These will be checked and must return true for the specified animation state to run. +- ```HasComponents``` Is true if the entity contains all specified components. + (For example: Coughing requiring a ```LungComponent```). +- ```MatchComponentPropertyValue``` Is true if the given component and datafield exists on an entity and has the specified value. + (For example: Blinking requiring the ```MobStateComponent``` with ```CurrentState``` being ```MobState.Alive```.) #### Triggers Used to trigger state condition checks, for example: - A wrapper around ```SubscribeLocalEvent()``` used for reacting to arbitrary events. -- ```ComponentAdded```/```ComponentRemoved``` +- ```ComponentAdded``` / ```ComponentRemoved``` -An implicit trigger is also executed when entities enter the client's rendering area. +An implicit trigger will be executed when entities enter the client's rendering area. The main reason for triggers is to minimize performance impact, as testing many conditions of several entities every frame could have a large impact on performance. #### Timers Allow animations to be played at fixed or random intervals -- ```RandomTimeRangeTimer```: Fires at random intervals inside a defined range. (For example: Blinking, Coughing) -- ```TimeIntervalTimer```: Fires at fixed intervals. (For example: Blinking indicator light) +- ```RandomTimeRangeTimer``` Fires at random intervals inside a defined range. (For example: Blinking, Coughing) +- ```TimeIntervalTimer``` Fires at fixed intervals. (For example: Blinking indicator light) ## Game Design Rationale -Animations are great for adding flavor and immersion to the game in many ways, the above mentioned examples just being a few. However, animations are currently difficult to implement correctly and require coding knowledge of animations as well as the system running said animations. The new system would be much easier to use, especially once YAML support for animations is implemented. +Animations are great for adding flavor and immersion to the game in many ways, the above mentioned examples just being a few. Animations are currently difficult to implement correctly and require coding knowledge of animations as well as the system running said animations. The new system would be much easier to use, especially once YAML support for animations is implemented. ## Roundflow & Player interaction -This is a background system, it does not affect roundflow and never requires a player to interact with it. +This will be a background system, it will not affect roundflow and should never require a player to interact with it. ## Administrative & Server Rule Impact (if applicable) N/A # Technical Considerations ## General -Ideally, the whole system should run client side. To account for triggers that depend on events which happen outside a player's rendering view; all state conditions are tested once an entity comes into view. If this should impact performance, a flag will be added to disable this trigger for animations where it's irrelevant. +Ideally, the whole system should run client side. To account for triggers that depend on events which happen outside a player's rendering view; all state conditions need to be tested once an entity comes into view. If this should impact performance, a flag will be added to disable this trigger for animations where it's irrelevant. Performance impact will heavily depend on how states are implemented. Many timers running at short intervals with subpar conditions could have a noticable performance impact - this can be mitigated through hard coded minimum intervals. @@ -60,14 +62,14 @@ While YAML defineable animations would be preferable, this should be doable usin ## SpriteComponent changes/refactor, yes or no? While a refactor of SpriteComponent has some advantages like not adding another system and automatically upgrading all sprites with ASM availability; this proposal is using an independent system due to the following reasons: -- The ASM could be used for more than sprites, i.e.: sound cues for coughing. +- The ASM could be used for more than sprites, for example: sound cues for coughing. - An independent system can be added and removed more easily from the engine. - The ASM component can be isolated to those entities that need it. (A piece of paper probably doesn't need animations). ## New Types -- ```AnimationStateMachineComponent``` Component to hold all state machines of an entity and their states. -- ```AnimationStateMachineSystem``` Client-side only system to execute the ASM's of all entities inside the players rendering view. -- ```AnimationStateMachineState``` Abstract base type for ASM states. -- ```AnimationStateMachineTrigger``` Abstract base type for triggers. -- ```AnimationStateMachineTimer``` Abstract base type for timers. -- ```AnimationStateMachineCondition``` Abstract base type for conditions. +- ```AnimationStateMachineComponent``` Component to hold all state machines of an entity and their states. +- ```AnimationStateMachineSystem``` Client-side only system to execute the ASM's of all entities inside the players rendering view. +- ```AnimationStateMachineState``` Abstract base type for ASM states. +- ```AnimationStateMachineTrigger``` Abstract base type for triggers. +- ```AnimationStateMachineTimer``` Abstract base type for timers. +- ```AnimationStateMachineCondition``` Abstract base type for conditions. From 6f961835971c6bd1b4210c30e7ec2e3c28aae44d Mon Sep 17 00:00:00 2001 From: Ataman Date: Thu, 11 Dec 2025 17:12:13 +0100 Subject: [PATCH 07/12] Renamed proposal file --- .../proposals/{proposal.md => animation-state-machine.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/en/space-station-14/core-tech/proposals/{proposal.md => animation-state-machine.md} (100%) diff --git a/src/en/space-station-14/core-tech/proposals/proposal.md b/src/en/space-station-14/core-tech/proposals/animation-state-machine.md similarity index 100% rename from src/en/space-station-14/core-tech/proposals/proposal.md rename to src/en/space-station-14/core-tech/proposals/animation-state-machine.md From 2a08e5f5a7f023db43a16523eb8b8769661b4798 Mon Sep 17 00:00:00 2001 From: Ataman Date: Thu, 11 Dec 2025 20:14:15 +0100 Subject: [PATCH 08/12] formatting --- .../core-tech/proposals/animation-state-machine.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/en/space-station-14/core-tech/proposals/animation-state-machine.md b/src/en/space-station-14/core-tech/proposals/animation-state-machine.md index 59bad84a91..1c1727408b 100644 --- a/src/en/space-station-14/core-tech/proposals/animation-state-machine.md +++ b/src/en/space-station-14/core-tech/proposals/animation-state-machine.md @@ -21,10 +21,8 @@ In order to define when these animations are supposed to run, hardcoded types fo #### Conditions These will be checked and must return true for the specified animation state to run. -- ```HasComponents``` Is true if the entity contains all specified components. - (For example: Coughing requiring a ```LungComponent```). -- ```MatchComponentPropertyValue``` Is true if the given component and datafield exists on an entity and has the specified value. - (For example: Blinking requiring the ```MobStateComponent``` with ```CurrentState``` being ```MobState.Alive```.) +- ```HasComponents``` Is true if the entity contains all specified components. (For example: Coughing requiring a ```LungComponent```). +- ```MatchComponentPropertyValue``` Is true if the given component and datafield exists on an entity and has the specified value. (For example: Blinking requiring the ```MobStateComponent``` with ```CurrentState``` being ```MobState.Alive```.) #### Triggers Used to trigger state condition checks, for example: From 3d8b7e9e11a75ba4348ca00954f0bc8d1534741c Mon Sep 17 00:00:00 2001 From: Ataman Date: Tue, 16 Dec 2025 10:46:18 +0100 Subject: [PATCH 09/12] Added BaseTriggerOnXComponent wrapper. --- .../core-tech/proposals/animation-state-machine.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/en/space-station-14/core-tech/proposals/animation-state-machine.md b/src/en/space-station-14/core-tech/proposals/animation-state-machine.md index 1c1727408b..a60b2a926c 100644 --- a/src/en/space-station-14/core-tech/proposals/animation-state-machine.md +++ b/src/en/space-station-14/core-tech/proposals/animation-state-machine.md @@ -27,8 +27,10 @@ These will be checked and must return true for the specified animation state to #### Triggers Used to trigger state condition checks, for example: - A wrapper around ```SubscribeLocalEvent()``` used for reacting to arbitrary events. +- A wrapper around ```BaseTriggerOnXComponent``` - ```ComponentAdded``` / ```ComponentRemoved``` + An implicit trigger will be executed when entities enter the client's rendering area. The main reason for triggers is to minimize performance impact, as testing many conditions of several entities every frame could have a large impact on performance. From bfba77e195acd0daff2000983ecdb907981992f2 Mon Sep 17 00:00:00 2001 From: Ataman Date: Tue, 16 Dec 2025 11:34:33 +0100 Subject: [PATCH 10/12] changed incorrect trigger comp --- .../core-tech/proposals/animation-state-machine.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/en/space-station-14/core-tech/proposals/animation-state-machine.md b/src/en/space-station-14/core-tech/proposals/animation-state-machine.md index a60b2a926c..da40fa3d56 100644 --- a/src/en/space-station-14/core-tech/proposals/animation-state-machine.md +++ b/src/en/space-station-14/core-tech/proposals/animation-state-machine.md @@ -27,10 +27,9 @@ These will be checked and must return true for the specified animation state to #### Triggers Used to trigger state condition checks, for example: - A wrapper around ```SubscribeLocalEvent()``` used for reacting to arbitrary events. -- A wrapper around ```BaseTriggerOnXComponent``` +- A wrapper around ```BaseXOnTriggerComponent``` - ```ComponentAdded``` / ```ComponentRemoved``` - An implicit trigger will be executed when entities enter the client's rendering area. The main reason for triggers is to minimize performance impact, as testing many conditions of several entities every frame could have a large impact on performance. From 9894ea94f4f31eb6ce5d22c2836949983b09d034 Mon Sep 17 00:00:00 2001 From: Ataman Date: Thu, 25 Dec 2025 14:01:12 +0100 Subject: [PATCH 11/12] updated and removed the SpriteComponent stuff --- .../proposals/animation-state-machine.md | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/en/space-station-14/core-tech/proposals/animation-state-machine.md b/src/en/space-station-14/core-tech/proposals/animation-state-machine.md index da40fa3d56..794d315b1f 100644 --- a/src/en/space-station-14/core-tech/proposals/animation-state-machine.md +++ b/src/en/space-station-14/core-tech/proposals/animation-state-machine.md @@ -5,7 +5,7 @@ | Ataman | Ataman | :x: No | TBD | ## Overview -This is a proposal to add an animation state machine (ASM) system that can be used to implement all kinds of temporary or persistent animations to entities like blinking eyes and waddling. The system would offer a framework consisting of timers, triggers, and conditions that can be defined in YAML to run these animations at the appropriate times. +This is a proposal to add a modular animation state machine (ASM) system that can be used to implement all kinds of temporary or persistent animations to entities like blinking eyes and waddling. The system would offer a framework consisting of timers, triggers, and conditions that can be defined in YAML to run these animations at the appropriate times. ## Background Things like blinking eyes and clown shoe waddling have been implemented in the past by creating specialized systems for their sole task of running simple animations under certain conditions. In almost every PR for these, one can find comments wishing for a more generalized animation system that could be used instead. @@ -26,7 +26,8 @@ These will be checked and must return true for the specified animation state to #### Triggers Used to trigger state condition checks, for example: -- A wrapper around ```SubscribeLocalEvent()``` used for reacting to arbitrary events. +- A small amount of periodically tested if-statements for stuff that doesn't have an event. +- A wrapper around event subscriptions (```SubscribeLocalEvent()```). - A wrapper around ```BaseXOnTriggerComponent``` - ```ComponentAdded``` / ```ComponentRemoved``` @@ -56,17 +57,21 @@ Performance impact will heavily depend on how states are implemented. Many timer This proposal ignores multi-state machines in favor of not adding more complexity to an already complex implementation. -## Animations don't support YAML -While YAML defineable animations would be preferable, this should be doable using hardcoded animations. If animations ever support YAML, this system can easily be updated to use those instead. +## Decoupling visuals +As already mentioned, previous implementations of certain visuals used strongly coupled components and systems for each of their unique behavior. This proposal aims to reduce that coupling down to a minimum and allow contributors to focus on the fun part, animating, while all the technical stuff gets hidden behind the ASM implementation. + +Blinking eyes could be implemented by inheriting an abstract class which overrides an ```Enter```/```Reset``` method and then add it to YAML. + +Clown waddling could be implemented by inheriting another abstract method and overriding the ```GetNextAnimation``` and ```GetResetAnimation```. -## SpriteComponent changes/refactor, yes or no? -While a refactor of SpriteComponent has some advantages like not adding another system and automatically upgrading all sprites with ASM availability; this proposal is using an independent system due to the following reasons: -- The ASM could be used for more than sprites, for example: sound cues for coughing. -- An independent system can be added and removed more easily from the engine. -- The ASM component can be isolated to those entities that need it. (A piece of paper probably doesn't need animations). +Using a proof-of-concept implementation on my fork; making mice do a cute little hop from time to time merely required 50 lines of C# code (including boiler-plate and comments) and 13 lines of YAML. + +## Animations don't support YAML +While YAML defineable animations would be preferable, this is doable using hardcoded animations. If animations ever support YAML, the system can easily be updated to use those instead. ## New Types -- ```AnimationStateMachineComponent``` Component to hold all state machines of an entity and their states. +- ```AnimationStateMachinePrototype``` Prototype for defining state machines. +- ```AnimationStateMachineComponent``` Component to hold all state machines of an entity. - ```AnimationStateMachineSystem``` Client-side only system to execute the ASM's of all entities inside the players rendering view. - ```AnimationStateMachineState``` Abstract base type for ASM states. - ```AnimationStateMachineTrigger``` Abstract base type for triggers. From 163bf244657340d91558de1a5686240b5a8f6faf Mon Sep 17 00:00:00 2001 From: Ataman Date: Sun, 28 Dec 2025 22:57:52 +0100 Subject: [PATCH 12/12] added paragraph about AnimationTrackComponentProperty safeguards --- .../core-tech/proposals/animation-state-machine.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/en/space-station-14/core-tech/proposals/animation-state-machine.md b/src/en/space-station-14/core-tech/proposals/animation-state-machine.md index 794d315b1f..61a3cddc52 100644 --- a/src/en/space-station-14/core-tech/proposals/animation-state-machine.md +++ b/src/en/space-station-14/core-tech/proposals/animation-state-machine.md @@ -33,7 +33,7 @@ Used to trigger state condition checks, for example: An implicit trigger will be executed when entities enter the client's rendering area. -The main reason for triggers is to minimize performance impact, as testing many conditions of several entities every frame could have a large impact on performance. +The main reason for triggers is to minimize performance impact, as testing many conditions of several entities every frame could have a large impact. #### Timers Allow animations to be played at fixed or random intervals @@ -66,6 +66,9 @@ Clown waddling could be implemented by inheriting another abstract method and ov Using a proof-of-concept implementation on my fork; making mice do a cute little hop from time to time merely required 50 lines of C# code (including boiler-plate and comments) and 13 lines of YAML. +## Other benefits +Animation tracks currently have no safeguards to prevent multiple animations editing the same property of a component simultaneously. This issue can be alleviated by adding validation methods inside the ASM. As a start, the ASM could keep track of any component properties currently in use on an entity and throw an error if another animation tries to use them. + ## Animations don't support YAML While YAML defineable animations would be preferable, this is doable using hardcoded animations. If animations ever support YAML, the system can easily be updated to use those instead.