DragonECS-Unity/README.md
2026-04-01 15:08:53 +08:00

18 KiB

Version GitHub Discord QQ

Integration with Unity for DragonECS

Readme Languages:

Русский

English(WIP)

This package integrates DragonECS with the Unity editor and runtime. It provides visual debugging and profiling tools, editor templates for entity/component setup, and utilities for binding entities to Unity GameObjects.

Warning

The project is a work in progress, API may change.

While the English version of the README is incomplete, the Russian README contains additional details.

//https://gist.github.com/DCFApixels/c250f2561f09e09ab3e6a4bd4f3013cb#file-unitycomponenttemplates-cs

Table of contents


Installation

Versioning semantics - Open

Environment

Requirements:

  • Dependency: DragonECS
  • Minimum C# version: 8.0
  • Minimum Unity version: 2021.2.0

Unity Installation

  • Unity package

Installation as a Unity package is supported by adding the Git URL in PackageManager:

https://github.com/DCFApixels/DragonECS-Unity.git

Or add the package entry to Packages/manifest.json:

"com.dcfa_pixels.dragonecs-unity": "https://github.com/DCFApixels/DragonECS-Unity.git",

Source install

The package sources can be copied directly into the project.


Debug

Debug service

UnityDebugService implementation of the Debug service for EcsDebug. In the editor it initializes automatically and integrates with Unity systems: EcsDebug.Print is forwarded to the Unity console, EcsProfilerMarker is connected to the Unity profiler, and related debug functionality is exposed.

// Activate manually
UnityDebugService.Activate();

// Print to Unity console
EcsDebug.Print("Example message");

var someMarker = new EcsProfilerMarker("SomeMarker");
someMarker.Begin();
// Measured time will be visible in the Unity profiler.
someMarker.End();

// Stop play mode
EcsDebug.Break();

Visual debugging

Visual debugging is provided as editor monitor objects that display internal framework state during Play Mode. Monitors are placed in the DontDestroyOnLoad section.

_pipeline = EcsPipeline.New()
    //...
    // Debugging initialization for the pipeline and worlds.
    .AddUnityDebug(_world, _eventWorld)
    //...
    .BuildAndInit();


  • PipelineMonitor

Displays EcsPipeline state. Systems are displayed in the order of their execution.


  • PipelineProcessMonitor

Displays processes and systems in a matrix layout. Systems are shown in execution order. A mark at the intersection of a system and a process indicates that the system is part of that process.


  • WorldMonitor

Displays EcsWorld state. A separate monitor is created for each world passed to AddUnityDebug(...).


  • EntityMonitor

Displays entity state and allows adding, modifying or removing components at runtime (Play Mode). One monitor is created per entity; entity monitors are grouped under the corresponding world monitor.



Templates

The integration provides templates that extend ITemplateNode for editor-driven entity configuration.

ScriptableEntityTemplate

Stored as a ScriptableObject asset.

Create asset: Asset > Create > DragonECS > ScriptableEntityTemplate.

To add a component to the Add Component menu, a component template is required.


MonoEntityTemplate

Attachable to a GameObject. Inherits from MonoBehaviour.

Add component: Add Component > DragonECS > MonoEntityTemplate.

To add a component to the Add Component menu, a component template is required.


Component Template

To expose a component in the Add Component menu, a template is required. Component templates are types implementing IComponentTemplate or components implementing ITemplateNode together with IEcsComponentMember.

Implementation

  • Simple example:
// Add [Serializable] attribute to the component type.
[Serializable]
struct SomeComponent : IEcsComponent { /* ... */ }
class SomeComponentTemplate : ComponentTemplate<SomeComponent> { }
// Same for tag components.
[Serializable]
struct SomeTagComponent : IEcsTagComponent { }
class SomeTagComponentTemplate : TagComponentTemplate<SomeTagComponent> { }
Other approaches

Implementing ITemplateNode on a component

This approach can be convenient because it does not require a separate template class; the component itself acts as the template and is straightforward to implement. The downside is higher risk of missing references when types are renamed if [SerializeReference] is used.

public struct Health : IEcsComponent, ITemplateNode
{
    public float Points;
    public void Apply(short worldID, int entityID)
    {
        EcsPool<Health>.Apply(worldID, entityID) = this;
    }
}

Custom template implementation

If built-in ComponentTemplate<T> or TagComponentTemplate<T> do not fit the requirements, implement a custom template by implementing IComponentTemplate. This can be useful for custom pools. In most cases the built-in templates are sufficient.

[Serializable] 
struct SomeComponent : IEcsComponent { /* ... */ }
class SomeComponentTemplate : IComponentTemplate
{
    [SerializeField]
    protected SomeComponent component;
    public Type Type { get { return typeof(SomeComponent); } }
    public bool IsUnique { get { return true; } }
    public void Apply(int worldID, int entityID)
    {
        EcsPool<SomeComponent>.Apply(worldID, entityID) = component;
    }
    public object GetRaw() { return component; }
    public void SetRaw(object raw) { component = (SomeComponent)raw; }
    public void OnGizmos(Transform transform, IComponentTemplate.GizmosMode mode) { /*...*/ }
    public void OnValidate(UnityEngine.Object obj) { /*...*/ }
}

Customizing type display

The Add Component dropdown supports hierarchical grouping based on the [MetaGroup] attribute.

By default components in the Inspector receive a deterministic color derived from the component name. The display mode can be changed in the settings window. A specific color can be set using the [MetaColor] attribute.

If the integration locates the corresponding script (by matching the type name to a file or via [MetaID]), a file icon appears next to the remove button — single-click selects the script in the project, double-click opens it.

If [MetaDescription] is present, a tooltip icon is shown with the description text.


Using component templates outside standard entity templates

Component templates can be used outside of MonoEntityTemplate and ScriptableEntityTemplate in arbitrary classes. Two approaches are provided:

Attribute [ComponentTemplateField]:

// Display a field as a component, customizable with meta attributes.
// Similar to components in MonoEntityTemplate or ScriptableEntityTemplate.
[SerializeField, ComponentTemplateField]
private SomeComponent _someComponent1;
// For SerializeReference adds a button to pick available ITemplateNode implementation
[SerializeReference, ComponentTemplateField]
private ITemplateNode _someComponent1;

Wrapper ComponentTemplateProperty:

// Wrapper around ITemplateNode, similar to the ComponentTemplateField example.
private ComponentTemplateProperty _someComponent2;

Both approaches work for arrays too:

[SerializeReference, ComponentTemplateField]
private IComponentTemplate[] _components;
// or
private ComponentTemplateProperty[] _components;

Binding to GameObjects

Entities and GameObjects are linked using connects. From the GameObject side use EcsEntityConnect; from the entity side GameObjectConnect is created/removed automatically. EcsEntityConnect acts as the manager connect.

EcsEntityConnect connect = /*...*/;
entlong entity = _world.NewEntityLong();

// Connect entity with GameObject.
// GameObjectConnect is added to the entity automatically
// and templates are applied.
connect.ConnectWith(entity);

// Or create without applying templates.
connect.ConnectWith(entity, false);

// Disconnect.
// GameObjectConnect will be removed automatically.
connect.Disconnect();
Add component: Add Component > DragonECS > EcsEntityConnect.

To view all components of the linked entity, expand RUNTIME COMPONENTS.

The bottom panel contains utility buttons: 1) Disconnect entity. 2) Delete entity. 3) Auto-fill template array. 4) Cascade auto-fill for all child connects in the hierarchy.


AutoEntityCreator automatically creates an entity and binds it to the GameObject. In the inspector specify the EcsEntityConnect to use and the world provider where the entity should be created.

Add component: Add Component > DragonECS > AutoEntityCreator.

The bottom panel includes helper buttons: 1) Auto-fill the connect reference. 2) Cascade auto-fill for all child instances in the hierarchy.


World Provider

EcsWorldProvider<TWorld> is a ScriptableObject wrapper over TWorld intended to expose a world instance via the Unity inspector. For simple scenarios the singleton provider EcsDefaultWorldSingletonProvider is sufficient.

// The singleton provider is created automatically under "Assets/Resource".
EcsDefaultWorldSingletonProvider provider = EcsDefaultWorldSingletonProvider.Instance;
// ...

EcsDefaultWorld world = new EcsDefaultWorld();
// Set the world instance to the provider.
provider.Set(world);

// ...

// Get the world instance; the provider will create a default world if empty.
EcsDefaultWorld world = provider.Get();

EcsPipeline pipeline = EcsPipeline.New()
    //...
    // Inject the provider world into systems.
    .Inject(world)
    //...
    .BuildAndInit();
Example: provider implementation for a custom world type
// Example implementation of a provider to expose a custom world type
[CreateAssetMenu(fileName = nameof(EcsMyWorldProvider), menuName = EcsConsts.FRAMEWORK_NAME + "/WorldProviders/" + nameof(EcsMyWorldProvider), order = 1)]
public class EcsMyWorldProvider : EcsWorldProvider<EcsMyWorld> { }

// Example singleton provider implementation for a custom world type
public class EcsMyWorldSingletonProvider : EcsWorldProvider<EcsMyWorld>
{
    private static EcsMyWorldSingletonProvider _instance;
    public static EcsMyWorldSingletonProvider Instance
    {
        get
        {
            if (_instance == null) { _instance = FindOrCreateSingleton<EcsMyWorldSingletonProvider>("SingletonMyWorld"); }
            return _instance;
        }
    }
}
Create provider asset: Asset > Create > DragonECS > WorldProviders > Select world type.


Pipeline templates

Pipelines and entities can be assembled from templates. Pipeline templates are modules implementing the IEcsModule interface.

The package provides two pipeline template types by default: ScriptablePipelineTemplate and MonoPipelineTemplate.

ScriptablePipelineTemplate

Stored as a ScriptableObject asset. Create via Asset > Create > DragonECS > ScriptablePipelineTemplate.

MonoPipelineTemplate

Attachable to a GameObject. Inherits from MonoBehaviour. Add via Add Component > DragonECS > MonoPipelineTemplate.


EcsRootUnity

Lightweight Ecs root implementation for Unity. Builds a pipeline from pipeline templates. Derives from MonoBehaviour. Add via Add Component > DragonECS > EcsRootUnity.


FixedUpdate and LateUpdate

using DCFApixels.DragonECS;
using UnityEngine;
public class EcsRoot : MonoBehaviour
{
    private EcsPipeline _pipeline;
    //...
    private void Update()
    {
        // Standard pipeline run.
        _pipeline.Run();
    }
    private void FixedUpdate()
    {
        // Pipeline run for FixedUpdate.
        _pipeline.FixedRun();
    }
    private void LateUpdate()
    {
        // Pipeline run for LateUpdate.
        _pipeline.LateRun();
    }
    // ...
}

Project documentation

A documentation window based on meta-attributes is available via Tools > DragonECS > Documentation. Documentation is generated on first open and when the Update button is pressed.


Settings window

The settings window exposes several options, including component display modes in the Inspector. At the bottom, toggles for framework define symbols are available. Open via Tools > DragonECS > Settings.


Reference Repairer

Some parts of the integration heavily use [SerializeReference], which can lose type information after renames. The Reference Repairer tool collects assets with missing types and provides an interface to map new type names and repair collected assets. Open via Tools > DragonECS > Reference Repairer.

If missing types have a [MetaID(id)] attribute, the tool attempts automatic mapping.


FAQ

Cannot add EcsEntityConnect or other components

This issue may appear after a package update. Recommended remediation steps: run Assets -> Reimport All, or close Unity, remove the project's Library folder and reopen the project.