### Setup StaticEcs World and Systems in Unity Source: https://felid-force-studios.github.io/StaticEcs/ru/unityintegrations.html This example demonstrates how to define ECS components, initialization systems, and update systems using StaticEcs. It shows the integration with Unity's MonoBehaviour lifecycle to manage world creation, component registration, and system execution. ```csharp using System; using FFS.Libraries.StaticEcs; using FFS.Libraries.StaticEcs.Unity; using UnityEngine; using Object = UnityEngine.Object; using Random = UnityEngine.Random; [StaticEcsEditorName("World")] public struct WT : IWorldType { } public abstract class W : World { } public abstract class WEvents : World.Events { } public struct SystemsType : ISystemsType { } public abstract class Systems : W.Systems { } public struct Position : IComponent { public Transform Value; } public struct Direction : IComponent { public Vector3 Value; } public struct Velocity : IComponent { public float Value; } [Serializable] public class WSceneData { public GameObject EntityPrefab; } public struct CreateRandomEntities : IInitSystem { public void Init() { for (var i = 0; i < 100; i++) { var go = Object.Instantiate(W.Context.Get().EntityPrefab); go.transform.position = new Vector3(Random.Range(0, 50), 0, Random.Range(0, 50)); W.Entity.New( new Position { Value = gameObject.transform }, new Direction { Value = new Vector3(Random.Range(-1f, 1f), 0, Random.Range(-1f, 1f)) }, new Velocity { Value = 2f }); } } } public struct UpdatePositions : IUpdateSystem { public void Update() { W.Query.For((W.Entity entity, ref Position position, ref Velocity velocity, ref Direction direction) => { position.Value.position += direction.Value * (Time.deltaTime * velocity.Value); }); } } public class Startup : MonoBehaviour { public WSceneData sceneData; private void Start() { W.Create(WorldConfig.Default()); W.RegisterComponentType(); W.RegisterComponentType(); W.RegisterComponentType(); EcsDebug.AddWorld(); AutoRegister.Apply(); W.Initialize(); W.Context.Set(sceneData); Systems.Create(); Systems.AddCallOnce(new CreateRandomEntities()); Systems.AddUpdate(new UpdatePositions()); Systems.Initialize(); EcsDebug.AddSystem(); } private void Update() { Systems.Update(); } private void OnDestroy() { Systems.Destroy(); W.Destroy(); } } ``` -------------------------------- ### World Creation and Component Registration (C#) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/serialization.html Demonstrates the creation of a StaticECS world ('WT') and the registration of various component types, including basic components, multi-components, and relation types. It also shows how to register tags with their unique GUIDs. ```csharp public struct WT : IWorldType { } public abstract class W : World { } public static void CreateWorld() { W.Create(WorldConfig.Default()); W.RegisterComponentType(new Name.Config()); W.RegisterComponentType(new Position.Config()); W.RegisterMultiComponentType(4, new Items.Config()); W.RegisterOneToManyRelationType(4, leftConfig: new Parent.Config(), rightConfig: new Childs.Config()); W.RegisterTagType(new("3a6fe6a2-9427-43ae-9b4a-f8582e3a5f90")); ``` -------------------------------- ### Additional Multi-Component Operations in C# Source: https://felid-force-studios.github.io/StaticEcs/ru/features/multicomponent.html Shows an example of how to create an array with the capacity of a multi-component, useful for operations that require a pre-allocated array of the same size. ```csharp var array = new Item[items.Capacity]; ``` -------------------------------- ### Accessing Relation Components (C#) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/relations.html Illustrates how to interact with relation components, which are treated as standard components in StaticECS. Examples show how to get a reference to a related entity using `Ref()` and check if an entity has all specified related components using `HasAllOf()`. ```csharp entity.Ref(); entity.HasAllOf(); ``` -------------------------------- ### Create Entities with Components (C#) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/component.html Entities can be created with components in several ways. You can create an empty entity and add components later, or create an entity with initial component values. The examples show creating entities using `New()`, `New(component)`, and `Add()`. ```csharp // Method 1 - when creating an entity (similar to Add() method) W.Entity entity = W.Entity.New(); // Or via value (similar to Put() method) // Be careful with AutoInit and AutoReset (see additional features) W.Entity entity = W.Entity.New(new Position(x: 1, y: 1, z: 2)); // Add component to entity and return ref value to component (in DEBUG mode, an error will occur if it already exists on the entity) ref var position = ref entity.Add(); // Add component to entity (in DEBUG mode, an error will occur if it already exists on the entity) (overload methods for 2-5 components) entity.Add(); // Add component to entity if it doesn't exist, otherwise return the existing one ref var position = ref entity.TryAdd(); ref var position = ref entity.TryAdd(out bool added); // overload where added = true if the component is new, false if an existing one was returned // Add component to entity if it doesn't exist (overload methods for 2-5 components) entity.TryAdd(); entity.TryAdd(out bool added); // overload where added = true if at least 1 component is new, false if all components previously existed // Place component via value. (overload methods for 1-5 components) // If the component already exists, all data will be replaced; if it doesn't exist, it will be created with the provided data. // Be careful with AutoInit and AutoReset (see additional features) entity.Put(new Position(x: 1, y: 1, z: 2)); ``` -------------------------------- ### Selective Serialization with EntitiesSnapshot Source: https://felid-force-studios.github.io/StaticEcs/ru/features/serialization.html Shows how to exclude specific components from serialization by omitting their GUID configuration and performing a manual snapshot of the world state. ```C# using var entitiesWriter = W.Serializer.CreateEntitiesSnapshotWriter(); entitiesWriter.WriteAllEntities(); byte[] snapshot = entitiesWriter.CreateSnapshot(); byte[] gidSnapshot = W.Serializer.CreateGIDStoreSnapshot(); byte[] eventsSnapshot = W.Events.CreateSnapshot(); // Deserialization: var gidStoreSnapshot = BinaryPack.ReadFromBytes(gidSnapshot); InitWorld(gidStoreSnapshot); W.Serializer.LoadEntitiesSnapshot(snapshot, entitiesAsNew: false); W.Events.LoadSnapshot(eventsSnapshot); ``` -------------------------------- ### Querying Entities with Relation Components (C#) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/relations.html Demonstrates how to use relation components within queries in StaticECS. The example shows a query that selects entities possessing both `Parent` and `Childs` relation components using the `All()` filter. ```csharp W.Query.Entities>(); ``` -------------------------------- ### GZIP Compression for World Snapshots Source: https://felid-force-studios.github.io/StaticEcs/ru/features/serialization.html Demonstrates how to enable and use GZIP compression when creating and loading world snapshots. This is useful for reducing the size of saved data. Ensure to specify `gzip: true` for both creation and loading if the snapshot was compressed. ```csharp byte[] snapshot = W.Serializer.CreateWorldSnapshot(gzip: true); W.Serializer.CreateWorldSnapshot("Path/to/save/data/world.bin", gzip: true); W.Serializer.LoadWorldSnapshot(snapshot, gzip: true); W.Serializer.LoadWorldSnapshot("Path/to/save/data/world.bin", gzip: true); ``` -------------------------------- ### Implement System Interfaces (IInitSystem, IUpdateSystem, IDestroySystem) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/systems.html Demonstrates the implementation of various system interfaces: IInitSystem for one-time initialization, IUpdateSystem for per-frame updates, and IDestroySystem for one-time cleanup. These can be combined for complex system behaviors. ```csharp // System IInitSystem - Init() method runs once during initialization public struct SomeInitSystem : IInitSystem { public void Init() { } } // System IUpdateSystem - Update() method runs every time MySystems.Update() is called public struct SomeUpdateSystem : IUpdateSystem { public void Update() { } } // System IDestroySystem - Destroy() method runs once when MySystems.Destroy() is called public struct SomeDestroySystem : IDestroySystem { public void Destroy() { } } // Combined system implementing Init and Destroy public struct SomeInitDestroySystem : IInitSystem, IDestroySystem { public void Init() { } public void Destroy() { } } // Combined system implementing Init, Update, and Destroy public struct SomeComboSystem : IInitSystem, IUpdateSystem, IDestroySystem { public void Init() { } public void Update() { } public void Destroy() { } } ``` -------------------------------- ### Get Tag Count on an Entity (C#) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/tag.html Provides the method to retrieve the total number of tags currently associated with an entity. This can be useful for debugging or conditional logic. ```csharp // Получить количество тегов на сущности int tagsCount = entity.TagsCount(); ``` -------------------------------- ### Save and Load World Snapshot on Initialization Source: https://felid-force-studios.github.io/StaticEcs/ru/features/serialization.html Demonstrates how to serialize an entire world state into a byte array or file during the initialization phase. This process captures all entities and events, allowing for a complete restoration of the world state. ```C# CreateWorld(); W.Initialize(); CreateEntities(); Console.WriteLine("Созданные сущности:"); foreach (var entity in W.Query.Entities()) { Console.WriteLine(entity.PrettyString); } byte[] worldSnapshot = W.Serializer.CreateWorldSnapshot(); W.Destroy(); CreateWorld(); W.InitializeFromWorldSnapshot(worldSnapshot); Console.WriteLine("Загруженые сущности:"); foreach (var entity in W.Query.Entities()) { Console.WriteLine(entity.PrettyString); } W.Destroy(); ``` -------------------------------- ### Manage World Snapshots and Persistence in StaticECS Source: https://felid-force-studios.github.io/StaticEcs/ru/features/serialization.html Demonstrates the complete lifecycle of creating, unloading, and reloading snapshots for entities, clusters, and chunks. It highlights the use of GIDStore snapshots to maintain entity identity across world destruction and reconstruction. ```csharp public static void PrintEntitiesCount(string text) { Console.WriteLine($"{text} - Всего {W.CalculateEntitiesCount()} | Загруженных {W.CalculateLoadedEntitiesCount()}"); } CreateWorld(); W.Initialize(); CreateEntities(); using var entitiesWriter = W.Serializer.CreateEntitiesSnapshotWriter(); foreach (var entity in W.Query.Entities()) { entitiesWriter.Write(entity); entity.Unload(); } byte[] individualEntitiesSnapshot = entitiesWriter.CreateSnapshot(); PrintEntitiesCount("После создания снимка конкретных сущностей:"); const ushort SOME_NEW_CLUSTER = 1; W.RegisterCluster(SOME_NEW_CLUSTER); for (int i = 0; i < 2000; i++) { W.Entity.New( new Position(i, i, i), new Name($"MovableCluster entity {i}"), clusterId: SOME_NEW_CLUSTER ); } PrintEntitiesCount("После создания кластера сущностей:"); byte[] clusterSnapshot = W.Serializer.CreateClusterSnapshot(SOME_NEW_CLUSTER); W.UnloadCluster(SOME_NEW_CLUSTER); PrintEntitiesCount("После выгрузки кластера сущностей:"); var chunkIdx = W.FindNextSelfFreeChunk().ChunkIdx; W.RegisterChunk(chunkIdx, W.DEFAULT_CLUSTER); for (int i = 0; i < 100; i++) { var entity = W.Entity.New(chunkIdx: chunkIdx); entity.Add( new Position(i, i, i), new Name($"Chunk {chunkIdx} entity {i}") ); } PrintEntitiesCount("После создания чанка сущностей:"); byte[] chunkSnapshot = W.Serializer.CreateChunkSnapshot(chunkIdx); W.UnloadChunk(chunkIdx); PrintEntitiesCount("После выгрузки чанка сущностей:"); byte[] gidSnapshot = W.Serializer.CreateGIDStoreSnapshot(); W.Destroy(); CreateWorld(); W.InitializeFromGIDStoreSnapshot(gidSnapshot); W.Serializer.LoadClusterSnapshot(clusterSnapshot); PrintEntitiesCount("После загрузки кластера сущностей:"); W.Serializer.LoadEntitiesSnapshot(individualEntitiesSnapshot); PrintEntitiesCount("После загрузки конкретных сущностей:"); W.Serializer.LoadChunkSnapshot(chunkSnapshot); PrintEntitiesCount("После загрузки чанка сущностей:"); W.Destroy(); ``` -------------------------------- ### EntityGID in Events Source: https://felid-force-studios.github.io/StaticEcs/ru/features/gid.html Illustrates how EntityGID is used within event structures, specifically in the 'DamageEvent' example. It shows how to access the target entity using its GID and apply damage. ```csharp public struct DamageEvent : IEvent { public EntityGID Target; public float Damage; } // In the system: foreach (var damageEvent in damageEventReceiver) { var val = weatherEvent.Value; if (val.Target.TryUnpack(out var entity)) { entity.Ref.Value -= val.Damage; //... } } ``` -------------------------------- ### Implement StaticECS World and Systems in C# Source: https://felid-force-studios.github.io/StaticEcs/ru This snippet demonstrates the core workflow of StaticECS, including defining component structs, creating an update system using queries, and managing the world lifecycle. It covers component registration, entity creation, and the execution of update loops. ```csharp using FFS.Libraries.StaticEcs; public struct WT : IWorldType { } public abstract class W : World { } public struct SystemsType : ISystemsType { } public abstract class Systems : W.Systems { } public struct Position : IComponent { public Vector3 Value; } public struct Direction : IComponent { public Vector3 Value; } public struct Velocity : IComponent { public float Value; } public readonly struct VelocitySystem : IUpdateSystem { public void Update() { W.Query.For((ref Position pos, ref Velocity vel, ref Direction dir) => { pos.Value += dir.Value * vel.Value; }); } } public class Program { public static void Main() { W.Create(WorldConfig.Default()); W.RegisterComponentType(); W.RegisterComponentType(); W.RegisterComponentType(); W.Initialize(); Systems.Create(); Systems.AddUpdate(new VelocitySystem()); Systems.Initialize(); var entity = W.Entity.New( new Velocity { Value = 1f }, new Position { Value = Vector3.Zero }, new Direction { Value = Vector3.UnitX } ); Systems.Update(); Systems.Destroy(); W.Destroy(); } } ``` -------------------------------- ### Define a Component (C#) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/component.html Components in StaticECS are represented as C# structs implementing the `IComponent` interface. This struct-based approach is chosen for performance reasons. The example shows a simple `Position` component. ```csharp public struct Position : IComponent { public Vector3 Value; } ``` -------------------------------- ### Register Component Types (C#) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/component.html Before components can be used, their types must be registered with the ECS world. This is typically done after creating the world but before initializing it. The example demonstrates registering the `Position` component type. ```csharp W.Create(WorldConfig.Default()); //... W.RegisterComponentType(); //... W.Initialize(); ``` -------------------------------- ### Save and Load Entities with GID Persistence in StaticECS Source: https://felid-force-studios.github.io/StaticEcs/ru/features/serialization.html Demonstrates the process of creating an entity snapshot and a GID store snapshot to preserve entity IDs across sessions. It shows how to initialize a world from a GID snapshot and load entities without reassigning IDs, ensuring relational integrity. ```C# CreateWorld(); W.Initialize(); CreateEntities(); Console.WriteLine("Созданные сущности:"); using var entitiesWriter = W.Serializer.CreateEntitiesSnapshotWriter(); foreach (var entity in W.Query.Entities()) { entitiesWriter.Write(entity); Console.WriteLine(entity.PrettyString); } byte[] snapshot = entitiesWriter.CreateSnapshot(); byte[] gidSnapshot = W.Serializer.CreateGIDStoreSnapshot(); W.Destroy(); CreateWorld(); W.InitializeFromGIDStoreSnapshot(gidSnapshot); var someEntity1 = W.Entity.New(new Position(1, 2, 3), new Name("someEntity1")); var someEntity2 = W.Entity.New(new Position(2, 3, 4), new Name("someEntity2")); W.Serializer.LoadEntitiesSnapshot(snapshot, entitiesAsNew: false); Console.WriteLine("Загруженые сущности:"); foreach (var entity in W.Query.Entities()) { Console.WriteLine(entity.PrettyString); } W.Destroy(); ``` -------------------------------- ### Configure Global Entity Creation Hooks Source: https://felid-force-studios.github.io/StaticEcs/ru/features/entity.html Shows how to register a callback that executes whenever a new entity is created within the world. ```C# W.Create(WorldConfig.Default()); W.OnCreateEntity(entity => entity.Add()); W.Initialize(); ``` -------------------------------- ### Manage Clusters: Register, Activate, Free, and Destroy Entities Source: https://felid-force-studios.github.io/StaticEcs/ru/features/world.html Demonstrates core cluster management operations such as registering, checking registration status, activating/deactivating, freeing, and destroying all entities within a cluster. It also shows how to attempt freeing a cluster safely. ```csharp // Регистрация кластера, может быть вызван после создания или после инициализации мира const ushort NPC_CLUSTER = 1; const ushort ENVIRONMENT_CLUSTER = 2; W.RegisterCluster(NPC_CLUSTER); W.RegisterCluster(ENVIRONMENT_CLUSTER); // Проверить зарегистрирован ли кластер bool clusterIsRegistered = W.ClusterIsRegistered(NPC_CLUSTER); // Включить или отключить кластер, сущности из отключенных кластеров не попадают в итерацию W.SetActiveCluster(ENVIRONMENT_CLUSTER, false); // Проверить включен ли кластер bool active = W.ClusterIsActive(ENVIRONMENT_CLUSTER); // Освободить кластер, все сущности в кластере будут удалены, все чанки и идентификатор кластера освобождены (Будет ошибка если кластер не зарегистрирован) W.FreeCluster(ENVIRONMENT_CLUSTER); // Освободить кластер если он зарегистрирован bool free = W.TryFreeCluster(ENVIRONMENT_CLUSTER); // Уничтожить все сущности в кластере W.DestroyAllEntitiesInCluster(NPC_CLUSTER); ``` -------------------------------- ### Registering and Using Multi-Components in C# Source: https://felid-force-studios.github.io/StaticEcs/ru/features/multicomponent.html Demonstrates how to register a multi-component type and add/manage it on an entity. It shows default and custom implementations for adding multi-components and accessing their elements. ```csharp W.RegisterMultiComponentType, Item>(defaultComponentCapacity: 4); // При добавлениие мультикомпонента по умолчанию вместимость будет defaultComponentCapacity, по мере добавления элементов будет расширяться // Добавление мультикомпонента как и обычного компонента // в случае дефолтной реализации ref var items = ref entity.Add>(); // в случае кастомной реализации ref var inventory = ref entity.Add(); ref var items = ref inventory.Items; // Доступны все остальные бызовые методы работы с компонентами entity.TryAdd>(); entity.HasAllOf>(); // ... // При удалении мультикомпонента - список элементов будет автоматически очищен entity.Delete>(); entity.TryDelete>(); // При копировании и перемещении мультикомпонента - будут автоматически скопированы все элементы entity.CopyComponentsTo>(entity2); entity.Clone(); entity.MoveComponentsTo>(entity2); entity.MoveTo(entity2); ``` -------------------------------- ### Basic Component Operations (C#) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/component.html This snippet covers fundamental operations on entity components, including getting component counts, referencing components for read/write, checking for component presence, and deleting components. It also includes methods for copying, disabling, and enabling components. ```csharp W.Entity entity = W.Entity.New( new Name { Val = "Player" }, new Velocity { Val = 1f }, new Position { Val = Vector3.One } ); // Get the number of components on the entity int componentsCount = entity.ComponentsCount(); // Get a ref link to the component for reading/writing ref var velocity = ref entity.Ref(); velocity.Val++; // Check if ALL specified components are present (overload methods for 1-3 components) entity.HasAllOf(); entity.HasAllOf(); // Check if at least one of the specified components is present (overload methods for 2-3 components) entity.HasAnyOf(); entity.HasAnyOf(); // Remove a component from the entity (in DEBUG mode, an error will occur if the component does not exist on the entity, in release, it should not be used if there is no guarantee that the component is present) (overload methods for 1-5 components) entity.Delete(); entity.Delete(); // Remove a component from the entity if it exists (overload methods for 1-5 components) bool deleted = entity.TryDelete(); // deleted = true if the component was deleted, false if it did not exist initially bool deleted = entity.TryDelete(); // deleted = true if ALL components were deleted, false if at least 1 component did not exist initially var entity2 = W.Entity.New(); // Copy specified components to another entity (overload methods for 1-5 components) entity.CopyComponentsTo(entity2); // Disables a component (by default, disabled components are not included in query filters (see Query)) (overload methods for 1-3 components) entity.Disable(); entity.Disable(); // Enables a component (overload methods for 1-3 components) entity.Enable(); entity.Enable(); // Check if ALL disabled components are present (overload methods for 1-3 components) bool positionDisabled = entity.HasDisabledAllOf(); bool positionAndVelocityDisabled = entity.HasDisabledAllOf(); // Check if at least one disabled component is present (overload methods for 1-3 components) bool anyPositionAndVelocityDisabled = entity.HasDisabledAnyOf(); // Check if ALL enabled components are present (overload methods for 1-3 components) bool positionEnabled = entity.HasEnabledAllOf(); bool positionAndVelocityEnabled = entity.HasEnabledAllOf(); // Check if at least one enabled component is present (overload methods for 1-3 components) bool anyPositionAndVelocityEnabled = entity.HasEnabledAnyOf(); ``` -------------------------------- ### Save and Load World Snapshot Post-Initialization Source: https://felid-force-studios.github.io/StaticEcs/ru/features/serialization.html Shows how to load a world snapshot into an already initialized world instance. This method clears existing entities and events before applying the snapshot data. ```C# CreateWorld(); W.Initialize(); CreateEntities(); byte[] worldSnapshot = W.Serializer.CreateWorldSnapshot(); W.Destroy(); CreateWorld(); W.Initialize(); W.Serializer.LoadWorldSnapshot(worldSnapshot); Console.WriteLine("Загруженые сущности:"); foreach (var entity in W.Query.Entities()) { Console.WriteLine(entity.PrettyString); } W.Destroy(); ``` -------------------------------- ### Delete Links and Configure Strategies Source: https://felid-force-studios.github.io/StaticEcs/ru/features/relations.html Shows how to remove links using TryDeleteLink and how to configure deletion strategies during registration to control automatic cleanup behavior. ```csharp // Deleting links sonAlex.TryDeleteLink(); sonJack.TryDeleteLink(); sonKevin.TryDeleteLink(); // Register with specific deletion strategy W.RegisterOneToManyRelationType(defaultComponentCapacity: 4, leftDeleteStrategy: Default); ``` -------------------------------- ### Register One-to-Many Relation Type with Custom Deletion Strategy (C#) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/relations.html Shows how to register a one-to-many relationship between `Parent` and `Childs` components. It highlights the `rightDeleteStrategy` parameter, which allows customization of how reverse links are handled upon deletion. The example uses the `Default` strategy, but `DestroyLinkedEntity` and `DeleteAnotherLink` are also available. ```csharp W.RegisterOneToManyRelationType(defaultComponentCapacity: 4, rightDeleteStrategy: Default); ``` -------------------------------- ### Manage Systems Lifecycle (Create, Add, Initialize, Update, Destroy) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/systems.html Illustrates the core operations for managing systems using the static Systems class. This includes creating the system type, adding various types of systems (call-once, update, conditional), and controlling their execution lifecycle (Initialize, Update, Destroy). ```csharp // Define the system identifier public struct SystemsType : ISystemsType { } // Define a type alias for convenient access to systems public abstract class Systems : W.Systems { } // Create systems Systems.Create(); // Add systems that are not IUpdateSystem (Init and/or Destroy) Systems.AddCallOnce(new SomeInitSystem()); Systems.AddCallOnce(new SomeDestroySystem()); Systems.AddCallOnce(new SomeInitDestroySystem()); // Add a system implementing IUpdateSystem Systems.AddUpdate(new SomeComboSystem()); // Add an update system with a specific order Systems.AddUpdate(new SomeComboSystem(), order: 3); // Systems run in the order they are added (default order 0) // Init systems run first, then Update systems in the game loop, then Destroy systems upon world destruction. // Systems can be structs or classes. Structs can improve performance for small systems. // Add systems in batches for performance gains. Each system must implement IUpdateSystem. Systems.AddUpdate( new SomeUpdateSystem1(), new SomeComboSystem1(), new SomeComboSystem2(), new SomeComboSystem3(), new SomeComboSystem4(), new SomeComboSystem5(), new SomeComboSystem() ); // Initialize all Init systems Systems.Initialize(); // Update all Update systems Systems.Update(); // Destroy all Destroy systems Systems.Destroy(); ``` -------------------------------- ### Cluster Serialization: Snapshot and Load Source: https://felid-force-studios.github.io/StaticEcs/ru/features/world.html Explains how to create a snapshot of a cluster's data for serialization and how to load a cluster from such a snapshot. This is useful for saving and restoring game state or transferring data. ```csharp // Сделать снимок кластера, который хранит все данные сущностей в этом кластере // Существуют перегрузки метода, для записи на диск, сжатию и тд // Больше примеров в разделе "сериализация" byte[] clusterSnapshot = W.Serializer.CreateClusterSnapshot(NPC_CLUSTER); // Выгрузить кластер из памяти, все чанки компонентов и тегов будут удалены, // сущности будут помечены как незагруженные и сохранится только информации об идентификаторах, сущности не будут получены в запросах W.UnloadCluster(NPC_CLUSTER); // Загрузить из снимка кластера сущности в мир W.Serializer.LoadClusterSnapshot(clusterSnapshot); ``` -------------------------------- ### Create EntityGID Source: https://felid-force-studios.github.io/StaticEcs/ru/features/gid.html Demonstrates how to obtain or create an EntityGID. It can be retrieved from an active entity or instantiated using its constructor with specific ID, version, and cluster ID, or directly from a raw value. ```csharp // Possible to get from an active entity EntityGID gid = entity.Gid(); // Or via constructor EntityGID gid2 = new EntityGID(id: 0, version: 1, clusterId: 0); EntityGID gid3 = new EntityGID(rawValue: 16777216UL); ``` -------------------------------- ### Create EntityGIDCompact Source: https://felid-force-studios.github.io/StaticEcs/ru/features/gid.html Shows how to create an EntityGIDCompact, which is a smaller version of EntityGID. It can be obtained from an active entity or created using a constructor with ID, version, and cluster ID, or from a raw value. ```csharp // Possible to get from an active entity EntityGIDCompact gid = entity.GidCompact(); // Or via constructor EntityGIDCompact gid2 = new EntityGIDCompact(id: 0, version: 1, clusterId: 0); EntityGIDCompact gid3 = new EntityGIDCompact(rawValue: 16777216U); ``` -------------------------------- ### Register and Initialize World with Tags (C#) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/tag.html Shows the necessary steps to initialize the StaticECS world and register custom tag types before initializing the world. This ensures that the tags are recognized and available for use. ```csharp W.Create(WorldConfig.Default()); //... W.RegisterTagType(); //... W.Initialize(); ``` -------------------------------- ### World Access Patterns Source: https://felid-force-studios.github.io/StaticEcs/ru/features/world.html Demonstrates three ways to access the StaticEcs World: direct generic access, using static imports for cleaner syntax, and creating a custom alias class for the most ergonomic usage. ```C# // 1. Direct access World.Create(WorldConfig.Default()); var entity = World.Entity.New(); // 2. Static imports using static FFS.Libraries.StaticEcs.World; Create(WorldConfig.Default()); var entity = Entity.New(); // 3. Alias class (Recommended) public abstract class W : World { } W.Create(WorldConfig.Default()); var entity = W.Entity.New(); ``` -------------------------------- ### Entity Creation in Chunks Source: https://felid-force-studios.github.io/StaticEcs/ru/features/world.html Methods for instantiating entities within specific chunks. ```APIDOC ## POST /entity/new ### Description Creates a new entity within a specified chunk. If the chunk is full, the operation may fail or return false. ### Parameters - **chunkIdx** (uint) - Required - The target chunk index ### Response #### Success Response (200) - **entity** (Entity) - The newly created entity instance - **created** (bool) - Status of the creation attempt ``` -------------------------------- ### Querying Entities and Components in StaticECS Source: https://felid-force-studios.github.io/StaticEcs/ru/features/query.html Demonstrates various ways to query entities and components using delegates. Supports filtering by component types, optional entity access, and passing external state via tuples or ref parameters to avoid heap allocations. ```C# W.Query.For(entity => { Console.WriteLine(entity.PrettyString); }); W.Query.For(static (ref Position pos, ref Velocity vel, ref Direction dir) => { pos.Value += dir.Value * vel.Value; }); W.Query.For(static (W.Entity ent, ref Position pos, ref Velocity vel, ref Direction dir) => { pos.Value += dir.Value * vel.Value; }); W.Query.For(deltaTime, static (ref float dt, W.Entity ent, ref Position pos, ref Velocity vel, ref Direction dir) => { pos.Value += dir.Value * vel.Value * dt; }); int count = 0; W.Query.For(ref count, static (ref int counter, W.Entity ent, ref Position pos, ref Velocity vel, ref Direction dir) => { pos.Value += dir.Value * vel.Value; counter++; }); ``` -------------------------------- ### Create Entities in StaticEcs Source: https://felid-force-studios.github.io/StaticEcs/ru/features/entity.html Demonstrates various methods for creating single or multiple entities, including initialization with components, cluster/chunk assignment, and conditional creation. ```C# // Single entity creation W.Entity entity = W.Entity.New(); W.Entity entity = W.Entity.New(); W.Entity entity = W.Entity.New(new Position(x: 1, y: 1, z: 2)); // Multiple entity creation uint count = 100; W.Entity.NewOnes(count); W.Entity.NewOnes(count, static entity => { /* init logic */ }); // Cluster and Chunk management var npc = W.Entity.New(clusterId: W.DEFAULT_CLUSTER); var created = W.Entity.TryNew(out var ent, clusterId: ENVIRONMENT_CLUSTER); ``` -------------------------------- ### Implement and Use System Conditions (ISystemCondition) Source: https://felid-force-studios.github.io/StaticEcs/ru/features/systems.html Shows how to implement the ISystemCondition interface to control when systems are updated. The ShouldUpdate() method determines if a system or group of systems should execute. This is useful for features like pausing the game. ```csharp // Implement ISystemCondition to add conditional logic class GamePauseCondition : ISystemCondition { private bool paused; public bool ShouldUpdate() => !paused; } // Add a conditional update for a single system // Systems.AddConditionalUpdate(new GamePauseCondition(), new SaveLoadSystem()); // Add conditional updates for a group of systems // Systems.AddConditionalUpdate( // new GamePauseCondition(), // // new SomeUpdateSystem1(), // new SomeComboSystem1(), // new SomeComboSystem2(), // new SomeComboSystem3(), // new SomeComboSystem4(), // new SomeComboSystem5(), // new SomeComboSystem() // ); ``` -------------------------------- ### Manage Cluster Chunks and Entity Creation Source: https://felid-force-studios.github.io/StaticEcs/ru/features/world.html Covers operations related to cluster chunks, including retrieving all chunks and only loaded chunks. It also demonstrates how to create new entities, specifying a cluster ID, and how to check if entity creation was successful. ```csharp // Получить все чанки в кластере (включая пустые чанки где нет загруженных сущностей) ReadOnlySpan chunks = W.GetClusterChunks(NPC_CLUSTER); // Получить все чанки в кластере в которых как минимум одна сущность загружена ReadOnlySpan loadedChunks = W.GetClusterLoadedChunks(NPC_CLUSTER); // При создании сущности можно передать идентификатор кластера (по умолчанию сущность создается в дефолтном кластере W.DEFAULT_CLUSTER = 0) var npc = W.Entity.New(clusterId: W.DEFAULT_CLUSTER); // Попытаться создать сущность в кластере, если мир зависим и в нем не осталось свободных идентификаторов сущностей то вернутся false var created = W.Entity.TryNew(out var ent, clusterId: ENVIRONMENT_CLUSTER); // Для всех перегрузок добавлен опциональный параметр идентификатора кластера W.Entity.New( new Position(), new Name(), clusterId: NPC_CLUSTER ); ``` -------------------------------- ### Migrate Component Version in StaticECS Source: https://felid-force-studios.github.io/StaticEcs/ru/features/serialization.html Demonstrates how to update a component schema by incrementing the version and implementing a MigrationReader to handle legacy data structures. This ensures backward compatibility when fields like Z-coordinates are added to existing components. ```C# public struct Position : IComponent { public float X, Y, Z; public class Config : DefaultComponentConfig where WorldType : struct, IWorldType { public override Guid Id() => new("b121594c-456e-4712-9b64-b75dbb37e611"); public override BinaryWriter Writer() { return (ref BinaryPackWriter w, in Position value) => { w.WriteFloat(value.X); w.WriteFloat(value.Y); w.WriteFloat(value.Z); }; } public override BinaryReader Reader() => (ref BinaryPackReader r) => new Position(r.ReadFloat(), r.ReadFloat(), r.ReadFloat()); public override byte Version() => 1; public override EcsComponentMigrationReader MigrationReader() { return (ref BinaryPackReader reader, World.Entity entity, byte version, bool disabled) => { if (version == 0) { return new Position(reader.ReadFloat(), reader.ReadFloat(), 0); } throw new Exception("Unknown version"); }; } } } ``` -------------------------------- ### World Lifecycle and Configuration Source: https://felid-force-studios.github.io/StaticEcs/ru/features/world.html Covers the primary operations for managing a world, including custom configuration, initialization, and cleanup. It demonstrates how to handle snapshots and inspect world state. ```C# public struct WT : IWorldType { } public abstract class W : World { } W.Create(new() { Independent = true, BaseComponentTypesCount = 64, ParallelQueryType = ParallelQueryType.Disabled }); W.Initialize(4096); // Accessing world subsystems W.Entity.New(); W.Context.Get(); // Cleanup W.Destroy(); bool initialized = W.IsInitialized(); ``` -------------------------------- ### Create Extension Methods for Component Access Source: https://felid-force-studios.github.io/StaticEcs/ru/performance.html Shows how to create high-performance extension methods that wrap direct component access. This approach maintains readability while achieving performance comparable to direct calls. ```csharp public static class PositionExtension { [MethodImpl(AggressiveInlining)] public static ref Position Position(this World.Entity entity) { return ref World.Components.Value.Ref(entity); } } ref var position = ref entity.Position(); ``` -------------------------------- ### Manage Links via Parent and Child Source: https://felid-force-studios.github.io/StaticEcs/ru/features/relations.html Demonstrates setting links from the parent side using SetLinks/TrySetLinks and from the child side using SetLink. The framework automatically synchronizes the reverse relationship. ```csharp // Parent side ref Childs childs = ref father.SetLinks(sonAlex, sonJack, sonKevin); ref Childs childs = ref father.TrySetLinks(sonAlex, sonJack, sonKevin); // Child side ref Parent sonAlexParent = ref sonAlex.SetLink(father); ref Parent sonJackParent = ref sonJack.SetLink(father); ref Parent sonKevinParent = ref sonKevin.SetLink(father); ``` -------------------------------- ### Registering Callbacks for Snapshot Operations Source: https://felid-force-studios.github.io/StaticEcs/ru/features/serialization.html Shows how to register callback functions that execute before or after snapshot creation and loading operations. These callbacks can be global or filtered by snapshot type (World, Entities, Cluster, Chunk). ```csharp // Registering global callbacks W.Serializer.RegisterPreCreateSnapshotCallback(param => Console.WriteLine("Entities or world `CreateSnapshot` start")); W.Serializer.RegisterPostCreateSnapshotCallback(param => Console.WriteLine("Entities or world `CreateSnapshot` finish")); W.Serializer.RegisterPreLoadSnapshotCallback(param => Console.WriteLine("Entities or world `LoadSnapshot` start")); W.Serializer.RegisterPostLoadSnapshotCallback(param => Console.WriteLine("Entities or world `LoadSnapshot` finish")); // Registering callbacks filtered by snapshot type W.Serializer.RegisterPreCreateSnapshotCallback(param => { if (param.Type == SnapshotType.Entities) { Console.WriteLine("Entities `CreateSnapshot` start"); } }); W.Serializer.RegisterPostCreateSnapshotCallback(param => { if (param.Type == SnapshotType.World) { Console.WriteLine("World `CreateSnapshot` finish"); } }); ``` -------------------------------- ### Optimize Component Access in StaticEcs Source: https://felid-force-studios.github.io/StaticEcs/ru/performance.html Demonstrates the performance difference between entity-based sugar methods and direct component access in IL2CPP. Direct access via World.Components provides significant performance improvements. ```csharp // производительность в il2Cpp (в Mono нет разницы) может быть лучше во втором варианте на 10-40% // это же касается тегов и всех остальных методов HasAllOf<>, Delete<> и тд ref var position = ref entity.Ref(); // сахарный метод через сущность ref var position = ref World.Components.Value.Ref(entity); // прямой вызов ``` -------------------------------- ### Manage Context Services in StaticEcs Source: https://felid-force-studios.github.io/StaticEcs/ru/features/context.html Demonstrates how to register, replace, check, and remove services within the StaticEcs Context. It highlights the requirement of one object per type and the clearOnDestroy lifecycle management. ```csharp public class UserService1 { } public class UserService2 { } // Register services in the context W.Context.Set(new UserService1(), clearOnDestroy: true); W.Context.Set(new UserService2()); // Replace an existing service without throwing an error W.Context.Replace(new UserService2()); // Check for existence bool has = W.Context.Has(); // Remove a service W.Context.Remove(); ``` -------------------------------- ### Multi-Component Dynamic Array Operations in C# Source: https://felid-force-studios.github.io/StaticEcs/ru/features/multicomponent.html Explains how to use multi-components as dynamic arrays, including checking capacity, count, emptiness, and accessing elements by index or iteration. It also covers adding, inserting, and ensuring sufficient size. ```csharp // Мультикомпонент ведет себя как динамический массив (список) // Доступны следующие операции: // Информационные: ushort capacity = items.Capacity; // Текущая вместимость ushort count = items.Count; // Количество элементов bool empty = items.IsEmpty(); // True если нет элементов bool notEmpty = items.IsNotEmpty(); // True если есть элементы bool full = items.IsFull(); // True если текущая емкость заполнена // Доступ: ref Item element = ref items[1]; // Индексатор ref Item first = ref items.First(); // Сслыка на первый элемент ref Item last = ref items.Last(); // Ссылка на последний элемент foreach (ref var item in items) { // Цикл foreach по ссылкам элементов //.. } for (int i = 0; i < items.Count; i++) { // Цикл for по элементам ref var item = ref items[i]; } // Добавление и расширение: items.Add(new Item()); // Добавить элемент items.Add(new Item("a"), new Item("b"), new Item("c"), new Item("d")); // Добавить элементы (1 - 4) items.Add(new[] { new Item("f"), new Item("g") }); // Добавить элементы из массива items.Add(new[] { new Item("f"), new Item("g") }, 1, 1); // Добавить элементы из массива c указанием старта и количества items.Add(ref entity2.Ref>()); // Добавить элементы из другого компонента items.Add(ref entity2.Ref>(), 1, 1); // Добавить элементы из другого компонента c указанием старта и количества items.InsertAt(idx: 1, new Item("e")); // Вставить элемент в указанный индекс, остальные элементы будут сдвинуты items.EnsureSize(10); // Обеспечить вместимость еще на N элементов если требуется items.Resize(16); // Расширить вместимость до N если требуется ``` -------------------------------- ### Registering MultiComponents in StaticEcs Source: https://felid-force-studios.github.io/StaticEcs/ru/features/multicomponent.html Demonstrates the two primary ways to define and register MultiComponents: using the default Multi wrapper or a custom struct implementing IMultiComponent. ```C# // Using default Multi public struct Item { public string Value; } W.Create(WorldConfig.Default()); W.RegisterMultiComponentType, Item>(defaultComponentCapacity: 4); W.Initialize(); // Using custom IMultiComponent public struct Inventory : IMultiComponent { public Multi Items; public int SomeUserData; public ref Multi RefValue(ref Inventory component) => ref component.Items; } W.Create(WorldConfig.Default()); W.RegisterMultiComponentType(defaultComponentCapacity: 4); W.Initialize(); ``` -------------------------------- ### Управление владельцем чанка Source: https://felid-force-studios.github.io/StaticEcs/ru/features/world.html Этот раздел описывает, как проверить и изменить тип владения чанком. Тип владения определяет, может ли чанк использоваться для создания новых сущностей через Entity.New(). ```csharp // Проверить владельца чанка // ChunkOwnerType.Self - значит что чанк управляется данным миром, только чанки с Self владением используются для создания сущностей через Entity.New() // - независимый мир по умолчанию имеет все чанки с Self владением // ChunkOwnerType.Other - значит что чанк не управляется данным миром, сущности созданные через Entity.New() никогда не будут созданы в этих чанках // - зависимы мир по умолчанию имеет все чанки с Other владением ChunkOwnerType owner = W.GetChunkOwner(chunkIdx); // Изменить тип владения чанка // Если владение меняется с Other на Self то чанк становится доступен для создания сущностей через Entity.New() // Если владение меняется с Self на Other то чанк становится недоступен для создания сущностей через Entity.New() W.ChangeChunkOwner(chunkIdx, ChunkOwnerType.Other); // Создание сущностей через Entity.New(gid) доступно для чанков только с типом владения Other // Создание сущностей через Entity.New(chunkIdx) доступно для чанков только с типом владения Self ```