A project primarily used to experiment with Mass, an ECS Framework
Explore the docs »
View Demo
·
Report Bug
·
Request Feature
- Gather resources to build a house
- Utilizes smart objects for querying resources in the world
- Uses state tree for AI logic management
- Bridges logic between Mass and game world through subsystems
OpenSimulationExample.mov
Old Videos
MassAITesting-GatherAI2.mp4
MassAITesting-Simulation.mp4
MassAITesting-GatheringEntities.mp4
- Entities utilize nav mesh to find optimal path to location
- Use async functionality to reduce overhead
- Uses State Tree
- Simple example outlining one approach to a save/load system
- Signal processor to write data
- Subsystem for centralized processing
- Uses current Unreal Save System
- Uses smart objects and state tree for mass entity interaction
- Claims then uses object, plays an example effect
- Barebones example which uses a custom state tree task to find a random location, then command the entity to move there
- Example for utilizing a spatial hash grid for fast queries in the world. The same underlying system is used for mass avoidance.
- Allows the user to query an area and returns entities that are within the range.
- Custom processor for updating entities location within the hash grid
- Simple example which outlines basic state tree logic (using mass).
- Utilizes tasks and nodes within the tree for organizing logic
- Showcases the Vertex Animation Plugin converting skeletal mesh animations to vertex animation.
- Barebones and mainly used in the Open Simulation example
These are my rough notes outlining discoveries made within mass and the city sample. Please don't expect anything well formatted, some things may even be outdated.
- Visualization Trait
- Mass Viewer Info Fragment
- Mass Actor Fragment (For actor visualization)
- Mass Visualization LOD Processor (Index 41)
- LODCollectorProcessor is disabled by default for some reason, which is needed when entity counts are high
- Mass LOD Collector Trait
- Mass LOD Collector Processor (Index 17)
- Using Assorted Fragments and Agent Radius Fragment will allow you to override the default radius of agents for the entity
- The height is simply interpolated based on the target location and current height. It should not be relied on to give completely accurate results when the distance is far. A possible solution would be to update the target location z during movement.
- Fragments hold data (FMassFragment)
- Filter entities using tags (FMassTag)
- Traits contain fragments/tags (UMassEntityTraitBase)
- Processors use fragment data to perform tasks on entities (UMassProcessor)
- StateTree and Fragments are sortof like BehaviorTree and Blackboard
- ObserverProcessors can observe more than one fragment/tag by overriding the Register() function.
- Evaluators basically gather data to be used in the state tree
- Enter Conditions are used on leaf nodes to see whether a leaf should be executed
- Tasks from ST are like BT, execute logic
- Transitions allow the state tree to go to other branches based on a condition
- Reference: https://docs.unrealengine.com/5.0/en-US/overview-of-state-tree-in-unreal-engine/
- Category for UPROPERTY in InstanceData determines what kind of value it is (Input, Output, Parameter)
- State Tree will throw an ensure when there are fragments missing for a task to execute. The only way I know to debug which fragments are missing is to goto the task and look for TStateTreeExternalDataHandle in the header file.
State Tree Experimental Findings
- Tick on StateTree Tasks are only ran once and with subscribed signals (see UMassStateTreeProcessor)
- I found no feasable way to subscribe signals in MassStateTreeProcessor. As a hacky solution just reuse one of the hardcoded signals
- A SmartObjectDefinition needs USmartObjectMassBehaviorDefinition and ALL default tag filters to show on Mass SmartObject Eval evaluator.
- UseSmartObjectTask will only execute USmartObjectMassBehaviorDefinition, meaning only C++ logic for the time
- Destroying a smart object safely in USmartObjectMassBehaviorDefinition should be done using PushCommand(). Lets the SmartObjectUseTask release the smart object before destruction. (may be source of ensures being fired, need to investigate further)
- Empty states with transitions seem to produce unexpected behavior. The state tree also always needs to be in an active state, even if idle.
- SmartObjectUseTask modifies MassMoveTarget around line 163-164, caused a headache since entities would not move after using a smart object.
- FMassSmartObjectHandler should be used rather than directly getting the smart object subsystem in mass....i think (seems to be used in~~~~ state tree tasks).
- Its possible to apply unique textures to each instance through an atlas and getting a random num to choose the frame - dont forget to use Vertex Interpolator and use a small float to fix precision issues.
- Vertex animation can be achieved by a similar tactic of using instance custom data to determine which animation to play
- To setup vertex animation, I used Vertex_Anim_Toolset and a UE5 fork
- In the processor, order is important when giving instance custom floats. FMassRepresentationFragment, FMassRepresentationLODFragment, and RepresentationSubsystem should be all you need to get started with instance custom data. (See URTSAnimationProcessor)
- Processors get their data from MassRepresentationSubsystem. At some point, actor templates are added via FindOrAddTemplateActor(). (Update: This is done for us most likely somewhere in the visualization/representation processors if you have actor visualization)
- The CDO is then retrieved via GetDefaultObject() and data can be retrieved. In this case, it is a CrowdCharacterDataAsset.
- A FCrowdCharacterDefinition is generated based on the data asset which contains the key info for animation among other things. (its a little more complex than described since the data is really retrieved from the FCrowdCharacterDefinition, just selected based on the human's properties)
- Finally, the animation data (UAnimToTextureDataAsset) is saved to the entities FCrowdAnimationFragment for future use in processors
- Note: Data assets appear to be added to the character BP (high actor visualization), this is why the data can be accessed.
- The actor can be retrieved using FMassRepresentationFragment.HighResTemplateActorIndex and RepresentationSubsystem->GetTemplateActorClass
- To be honest, a simple SharedFragment is probably sufficient for simple use-cases. I definitely might change my mind when I attempt to sync actor/ISM animation
- Actual anim state index is updated in UMassProcessor_Animation and custom data is updated at UMassCrowdUpdateISMVertexAnimationProcessor::UpdateISMVertexAnimation in various processors
- TPointHashGrid3 performance is considerably worse compared to THierarchicalHashGrid2D
- This could be caused by the extra dimension, testing scenario, or more efficient logic for mass (as THierarchicalHashGrid2D is used in MassAvoidance)
- Worst case scenario for similar search query: 235.9μs -> 8μs (x30 performance boost!)
- Find a way to use Mass SmartObject Eval effectively in the State Tree (DONE)
- Convert logic in RTSMovementProcessor to State Tree (KINDOF DONE)
- Agent gets stuck after using one smart object, find out why (DONE)
- The UseSmartObject task also messes with the MoveTargetFragment. It seems to be doing some stuff in ActivateActionAnimate() at MassZoneGraphNavigationUtils too. (DONE)