{"id":13663262,"url":"https://github.com/actionk/ECSEntityBuilder","last_synced_at":"2025-04-25T13:32:31.862Z","repository":{"id":53151984,"uuid":"247810195","full_name":"actionk/ECSEntityBuilder","owner":"actionk","description":"Unity ECS Entity Builder/Wrapper","archived":false,"fork":false,"pushed_at":"2023-01-11T08:16:15.000Z","size":168,"stargazers_count":47,"open_issues_count":0,"forks_count":8,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-11-10T19:34:50.916Z","etag":null,"topics":["builder","dots","ecs","entities","monstack","unity"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/actionk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-16T20:27:49.000Z","updated_at":"2024-08-14T15:27:50.000Z","dependencies_parsed_at":"2023-02-09T02:16:31.618Z","dependency_job_id":null,"html_url":"https://github.com/actionk/ECSEntityBuilder","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/actionk%2FECSEntityBuilder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/actionk%2FECSEntityBuilder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/actionk%2FECSEntityBuilder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/actionk%2FECSEntityBuilder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/actionk","download_url":"https://codeload.github.com/actionk/ECSEntityBuilder/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250825098,"owners_count":21493394,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["builder","dots","ecs","entities","monstack","unity"],"created_at":"2024-08-02T05:02:22.718Z","updated_at":"2025-04-25T13:32:26.806Z","avatar_url":"https://github.com/actionk.png","language":"C#","funding_links":[],"categories":["ECS Libraries","C\\#","Open Source Repositories"],"sub_categories":["DOTS"],"readme":"# Unity ECS EntityBuilder\n\nThis project is a wrapper around Unity ECS entities that allows one to simplify the process of creating / modifying entities.\n\n## Install\n\nYou can either just put the files into `Assets/Plugins/ECSEntityBuilder` or use it as a submodule:\n```\ngit submodule add https://github.com/actionk/UnityECSEntityBuilder.git Assets/Plugins/ECSEntityBuilder\n```\n\n# Usage\n\n## EntityWrapper\n\n### Wrapping an existing entity\n\nEntity Wrapper allows you to wrap `Entity` with an object a modify it without the need of passing the Entity reference to the EntityManager over and over again.\n\n```cs\nvar entityWrapper = new EntityWrapper(entity)\n    .SetComponentData(new Translation { Value = float3.zero });\n    .AddBuffer\u003cTaskBufferElement\u003e();\n    .AddBuffer(\n        new PathPositionBufferElement {position = new int2(0, 1)},\n        new PathPositionBufferElement {position = new int2(0, 2)}\n    );\n```\n\nYou can also specify target entity manager / command buffer when creating a wrapper:\n\n```cs\nEntityWrapper.Wrap(entity, PostUpdateCommands)\n    .AddBuffer\u003cMyBuffer\u003e()\n    .SetComponentData(new Translation {Value = command.position})\n    .SetComponentData(new Scale {Value = 1.0f});\n```\n\n### Creating an entity\n\nApart of modifying, you can also create the entities using the EntityWrapper:\n\n```cs\nEntityWrapper.CreateEntity(EntityManager)\n    .AddBuffer\u003cMyBuffer\u003e()\n    .SetComponentData(new Translation {Value = command.position})\n    .SetComponentData(new Scale {Value = 1.0f});\n```\n\nIn this case, you pass the EntityManager or a command buffer into the `CreateEntity` method and the wrapper will do the rest for you.\n\n## EntityManagerWrapper\n\nEntityManagerWrapper wraps around different ways of accessing EntityManager:\n1. EntityManager\n```cs\nEntityManagerWrapper.Default\n```\n\n2. EntityCommandBuffer (PostUpdateCommands)\n```cs\nEntityManagerWrapper.FromCommandBuffer(PostUpdateCommands)\n```\n\n3. EntityCommandBuffer.Concurrent (Jobs)\n```cs\nEntityManagerWrapper.FromJobCommandBuffer(commandBuffer, threadId);\n```\n\nUsage example:\n```cs\nvar entityWrapper = new EntityWrapper(entity);\nentityWrapper.UsingWrapper(EntityManagerWrapper.FromCommandBuffer(PostUpdateCommands), wrapper =\u003e\n{\n    wrapper.AddComponentData(new Rotation());\n    wrapper.AddElementToBuffer(new PathPositionBufferElement {position = new int2(2, 0)});\n});\n```\n\nOr using the builder:\n```cs\nvar entityManagerWrapper = EntityManagerWrapper.FromJobCommandBuffer(commandBuffer, threadId);\n\nUnitTaskBuilder\n    .CreateCombined(itemPosition)\n    .AddInnerTasks(\n        UnitTaskBuilder.CreateInner(new PickUpItemTaskData {itemEntity = itemEntityToPickUp}).Build(entityManagerWrapper),\n        UnitTaskBuilder.CreateInner(new PutItemToStorageTaskData {storageEntity = storageEntity}).Build(entityManagerWrapper)\n    )\n    .Build(entityManagerWrapper);\n```\n\n## EntityBuilder\n\n```cs\npublic class ItemBuilder : EntityBuilder\u003cItemBuilder\u003e\n{\n    public static ItemBuilder Create(ItemData itemData)\n    {\n        return new ItemBuilder(itemData);\n    }\n\n    protected override ItemBuilder Self =\u003e this;\n\n    internal ItemBuilder(ItemData itemData)\n    {\n        var contentItem = DependencyProvider.Resolve\u003cContentItemRepository\u003e().GetByKey(itemData.itemId);\n\n        CreateFromArchetype\u003cArchetypeItem\u003e();\n        this.SetSpriteRenderer(contentItem.icon);\n        SetVariable(new ZIndexVariable(SpriteLayers.OBJECT));\n        SetComponentData(itemData);\n        SetComponentData(new Scale {Value = 0.5f});\n    }\n}\n```\n\nUsage:\n```cs\nvar itemEntity = ItemBuilder\n    .Create(contentObject.gatheredResource)\n    .SetPosition(EntityManager.GetComponentData\u003cTranslation\u003e(taskData.objectEntity).Value)\n    .Build(PostUpdateCommands);\n```\n\nYou can pass the EntityManagerWrapper into the `Build()` function.\n\n### Defining Archetypes\n\nFor defining an archetype you can just create a class implementing `IArchetypeDescriptor`:\n\n```cs\npublic class ArchetypeItem : IArchetypeDescriptor\n{\n    public string Name =\u003e \"Item\";\n\n    public ComponentType[] Components =\u003e new ComponentType[]\n    {\n        // common\n        typeof(LocalToWorld),\n        typeof(Translation),\n        typeof(Rotation),\n        typeof(Scale),\n\n        // rendering\n        typeof(MeshRendererData),\n\n        // type-specific\n        typeof(TagItem),\n        typeof(ObjectData),\n        typeof(ItemData)\n    };\n}\n```\n\nAnd then to create it inside the builder:\n```cs\nCreateFromArchetype\u003cArchetypeItem\u003e();\n```\n\n### Initialising Archetypes\n\nAs you can only create archetypes in main thread by using EntityManager (not possible via EntityCommandBuffer), you can initialise your archetypes beforehand:\n\n```cs\nEntityArchetypeManager.Instance.InitializeArchetypes(\n    // tasks\n    typeof(ArchetypeCombinedUnitTask),\n    typeof(ArchetypeSingleUnitTask),\n    typeof(ArchetypeInnerUnitTask),\n\n    // items\n    typeof(ArchetypeItem),\n\n    // zones\n    typeof(ArchetypeZone),\n    typeof(ArchetypeZoneCell),\n\n    // objects\n    typeof(ArchetypeDecoration),\n    typeof(ArchetypeBuildingGround),\n\n    // generic\n    typeof(ArchetypeGenericObjectWithLocation)\n);\n```\n\nAlternatively, you can initialize archetypes by marking those classes with [Archetype] attribute:\n\n```cs\n[Archetype]\npublic class ArchetypeZone : IArchetypeDescriptor\n{\n    public string Name =\u003e \"Zone\";\n\n    public ComponentType[] Components =\u003e new ComponentType[]\n    {\n        ... components ...\n    };\n}\n```\n\nThen you can initialize archetypes for all the marked classes in this assembly with:\n\n```cs\nEntityArchetypeManager.Instance.InitializeArchetypes(Assembly.GetCallingAssembly());\n```\n\n### Initialising Archetypes in specific worlds\n\nBy default all the archetypes will be initialized in World.DefaultGameObjectInjectWorld\nIf you want to change this, you can specify the world by passing World parameter in the Attribute:\n\n```cs\n[Archetype(WorldType.SERVER)]\npublic class ServerPlayerArchetype : IArchetypeDescriptor\n```\n\n### Extending the EntityWrapper/EntityBuilder\n\nYou can easily add your own methods to EntityWrapper:\n\n```cs\npublic static class EntityWrapper2DExtensions\n{\n    public static void SetPosition2D(this EntityWrapper wrapper, int2 position)\n    {\n        wrapper.SetComponentData(new Translation {Value = new float3(position.x + 0.5f, position.y + 0.5f, 0)});\n    }\n}\n```\n\nOr to EntityBuilder:\n\n```cs\npublic static class EntityBuilder2DExtensions\n{\n    public static T SetPosition2D\u003cT\u003e(this EntityBuilder\u003cT\u003e wrapper, int2 position)\n    {\n        return wrapper.AddStep(new SetPosition2D(position));\n    }\n}\n\npublic class SetPosition2D : IEntityBuilderStep\n{\n    private readonly int2 position;\n\n    public SetPosition2D(int2 position)\n    {\n        this.position = position;\n    }\n\n    public void Process(EntityManagerWrapper wrapper, EntityVariableMap variables, ref EntityBuilderData data)\n    {\n        wrapper.SetComponentData(data.entity, new Translation {Value = new float3(position.x + 0.5f, position.y + 0.5f, 0)});\n    }\n}\n```\n\n### Additional functionality on Build()\n\nTo add your own Build implementation and access the EntityManager that was used for building, you can overload a `OnBuild` method:\n\n```cs\npublic override void OnBuild(EntityManagerWrapper wrapper, Entity dataEntity)\n{\n    // your building code\n}\n```\n\n### Mapping GameObjects with the built entity\n\nYou can create a game object inside a builder and link it with the created entity without using `ConvertToEntity` component.\n\n```cs\nprotected override void OnPreBuild(EntityManagerWrapper wrapper)\n{\n    base.OnPreBuild(wrapper);\n\n    var prefab = ResourceProvider.GetPrefab(\"Items/Item\");\n    var gameObject = GameObjectEntityManager.Instance.CreateFromPrefab(prefab);\n\n    AddComponentData(new ManagedGameObject {instanceId = gameObject.GetInstanceID()});\n}\n```\n\n### Variables\n\nWhen extending the `EntityWrapper` you might want to save some data in the wrapper to reuse it in your extensions. For example, when setting the 2D position, you might want to save ZIndex to be used for this exact entity.\n\n```cs\npublic class ZIndexVariable : IEntityVariable\n{\n    public int zIndex;\n\n    public ZIndexVariable(int zIndex)\n    {\n        this.zIndex = zIndex;\n    }\n}\n```\n\nAnd then extend the EntityBuilder:\n\n```cs\npublic class SetPosition2D : IEntityBuilderStep\n{\n    private const float ZIndexMultiplier = 0.01f;\n    private readonly int2 position;\n\n    public SetPosition2D(int2 position)\n    {\n        this.position = position;\n    }\n\n    private Translation GetTranslation(EntityVariableMap variables)\n    {\n        var zIndex = variables.Get\u003cZIndexVariable\u003e()?.zIndex ?? 0;\n        return new Translation {Value = new float3(position.x + 0.5f, position.y + 0.5f, -zIndex * ZIndexMultiplier)};\n    }\n\n    public void Process(EntityManagerWrapper wrapper, EntityVariableMap variables, ref EntityBuilderData data)\n    {\n        wrapper.SetComponentData(data.entity, GetTranslation(variables));\n    }\n}\n```\n\nUsage:\n\n```cs\nObjectBuilder.Create(6)\n    .SetVariable(new ZIndexVariable(10));\n    .SetPosition2D(new int2 {x = -7, y = 0})\n    .Build();\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Factionk%2FECSEntityBuilder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Factionk%2FECSEntityBuilder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Factionk%2FECSEntityBuilder/lists"}