Removed Ghost.ArcEntities project, it's replaced by Ghost.Entities

Added Playback to EntityCommandBuffer
Added JobSchedular to world
Added ISystem and SystemGroup
Updated packages
This commit is contained in:
2025-12-08 20:44:56 +09:00
parent f44208b502
commit 5e276b289d
30 changed files with 2974 additions and 1597 deletions

View File

@@ -1,5 +1,8 @@
using Ghost.Core;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
using Misaki.HighPerformance.LowLevel.Utilities;
using System.Runtime.InteropServices;
namespace Ghost.Entities;
@@ -17,18 +20,24 @@ public unsafe class EntityCommandBuffer : IDisposable
private struct Command
{
public UnsafeArray<byte> data;
public CommandType type;
public Entity entity;
public int componentTypeID;
public CommandType type;
public Identifier<IComponent> componentTypeID;
}
private readonly EntityManager _entityManager;
private UnsafeList<Command> _commands; // TODO: Maybe use UnsafeArray<byte> directly?
private UnsafeList<Command> _commands; // TODO: Maybe use UnsafeArray<byte> directly to save additional memory allocation in Unsafe<byte> data inside Command struct.
private bool _disposed;
public EntityCommandBuffer(EntityManager entityManager)
{
_entityManager = entityManager;
_commands = new UnsafeList<Command>(32, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
_commands = new UnsafeList<Command>(32, Allocator.Persistent);
}
~EntityCommandBuffer()
{
Dispose();
}
public void CreateEntity()
@@ -44,48 +53,107 @@ public unsafe class EntityCommandBuffer : IDisposable
_commands.Add(command);
}
public void DestroyEntity(Entity entity)
public void CreateEntity(params ReadOnlySpan<Identifier<IComponent>> componentTypeIDs)
{
var data = new UnsafeArray<byte>(componentTypeIDs.Length * sizeof(int), Allocator.Temp);
MemoryMarshal.Cast<Identifier<IComponent>, byte>(componentTypeIDs).CopyTo(data.AsSpan());
var command = new Command
{
type = CommandType.DestroyEntity,
data = default,
entity = entity,
componentTypeID = -1
type = CommandType.CreateEntity,
data = data,
entity = Entity.Invalid,
componentTypeID = Identifier<IComponent>.Invalid
};
_commands.Add(command);
}
public void AddComponent<T>(Entity entity, T component)
public void DestroyEntity(Entity entity)
{
_commands.Add(new Command
{
type = CommandType.DestroyEntity,
data = default,
entity = entity,
componentTypeID = Identifier<IComponent>.Invalid
});
}
public void AddComponent<T>(Entity entity, T component = default)
where T : unmanaged, IComponent
{
var data = new UnsafeArray<byte>(sizeof(T), Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
MemoryUtility.MemCpy(&component, data.GetUnsafePtr(), (nuint)sizeof(T));
var data = new UnsafeArray<byte>(sizeof(T), Allocator.Temp);
MemoryUtility.MemCpy(data.GetUnsafePtr(), &component, (nuint)sizeof(T));
var command = new Command
_commands.Add(new Command
{
type = CommandType.AddComponent,
data = data,
entity = entity,
componentTypeID = ComponentTypeID<T>.value
};
_commands.Add(command);
});
}
public void RemoveComponent<T>(Entity entity)
where T : unmanaged, IComponent
{
var command = new Command
_commands.Add(new Command
{
type = CommandType.RemoveComponent,
data = default,
entity = entity,
componentTypeID = ComponentTypeID<T>.value
};
});
}
_commands.Add(command);
public void SetComponent<T>(Entity entity, T component)
where T : unmanaged, IComponent
{
var data = new UnsafeArray<byte>(sizeof(T), Allocator.Temp);
MemoryUtility.MemCpy(data.GetUnsafePtr(), &component, (nuint)sizeof(T));
_commands.Add(new Command
{
type = CommandType.SetComponent,
data = data,
entity = entity,
componentTypeID = ComponentTypeID<T>.value
});
}
internal void Playback()
{
foreach (ref var command in _commands)
{
switch (command.type)
{
case CommandType.CreateEntity:
if (command.data.Count > 0)
{
_entityManager.CreateEntity(MemoryMarshal.Cast<byte, Identifier<IComponent>>(command.data.AsSpan()));
}
else
{
_entityManager.CreateEntity();
}
break;
case CommandType.DestroyEntity:
_entityManager.DestroyEntity(command.entity);
break;
case CommandType.AddComponent:
_entityManager.AddComponent(command.entity, command.componentTypeID, command.data.GetUnsafePtr());
break;
case CommandType.RemoveComponent:
_entityManager.RemoveComponent(command.entity, command.componentTypeID);
break;
case CommandType.SetComponent:
_entityManager.SetComponent(command.entity, command.componentTypeID, command.data.GetUnsafePtr());
break;
}
}
Reset();
}
public void Reset()
@@ -100,11 +168,19 @@ public unsafe class EntityCommandBuffer : IDisposable
public void Dispose()
{
if (_disposed)
{
return;
}
foreach (ref var command in _commands)
{
command.data.Dispose();
}
_commands.Dispose();
_disposed = true;
GC.SuppressFinalize(this);
}
}