forked from Misaki/GhostEngine
Refactor project structure and enhance functionality
Changed the project namespace from `Ghost.Editor` to `Ghost.App` across multiple files. Changed the `InternalsVisibleTo` attribute in `AssemblyInfo.cs` to include `Ghost.App`. Changed the `ProjectRepository` class to add new asynchronous methods for retrieving projects by ID, name, and metadata path. Changed the `ProjectService` class to utilize the new asynchronous project loading methods. Changed the `SceneGraph` classes to improve node management and serialization. Changed the `EntityManager` class to enhance entity management with new component handling methods. Added new test classes, `EntityTest` and `SerializationTest`, to ensure reliability in entity and serialization systems. Added the `Ghost.App` project file to establish a modular project structure. Added the `Ghost.Generator` project for automated component serialization code generation. Updated UI components to reflect the new namespace for proper functionality.
This commit is contained in:
@@ -5,7 +5,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ghost.Entities;
|
||||
public struct EntityManager : IDisposable
|
||||
public readonly struct EntityManager : IDisposable
|
||||
{
|
||||
private readonly List<Entity> _entities;
|
||||
private readonly Queue<EntityID> _freeEntitySlots;
|
||||
@@ -15,11 +15,6 @@ public struct EntityManager : IDisposable
|
||||
public readonly int EntityCount => _entities.Count;
|
||||
public readonly ReadOnlySpan<Entity> Entities => CollectionsMarshal.AsSpan(_entities);
|
||||
|
||||
public event Action<Entity>? OnEntityCreated;
|
||||
public event Action<EntityID>? OnEntityRemoved;
|
||||
public event Action<Entity, Type>? OnComponentAdded;
|
||||
public event Action<Entity, Type>? OnComponentRemoved;
|
||||
|
||||
internal EntityManager(World world, int initialCapacity)
|
||||
{
|
||||
_entities = new(initialCapacity);
|
||||
@@ -45,10 +40,14 @@ public struct EntityManager : IDisposable
|
||||
_entities.Add(entity);
|
||||
}
|
||||
|
||||
OnEntityCreated?.Invoke(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
internal readonly void AddEntityInternal(Entity entity)
|
||||
{
|
||||
_entities.Add(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified <see cref="Entity"/> from the world.
|
||||
/// </summary>
|
||||
@@ -67,7 +66,6 @@ public struct EntityManager : IDisposable
|
||||
_entities[entity.ID] = slot;
|
||||
_freeEntitySlots.Enqueue(entity.ID);
|
||||
|
||||
OnEntityRemoved?.Invoke(entity.ID);
|
||||
entity = Entity.Invalid;
|
||||
}
|
||||
|
||||
@@ -88,6 +86,20 @@ public struct EntityManager : IDisposable
|
||||
return _entities[entity.ID].Generation == entity.Generation;
|
||||
}
|
||||
|
||||
public readonly void AddComponent(Entity entity, IComponentData component, Type type)
|
||||
{
|
||||
var typeHandle = TypeHandle.Get(type);
|
||||
ref var pool = ref CollectionsMarshal.GetValueRefOrAddDefault(_world.ComponentStorage.ComponentPools, typeHandle, out var exists);
|
||||
if (!exists)
|
||||
{
|
||||
var poolType = typeof(ComponentPool<>).MakeGenericType(type);
|
||||
pool = (IComponentPool)(Activator.CreateInstance(poolType) ?? throw new InvalidOperationException($"Failed to create component pool for type {type}."));
|
||||
}
|
||||
|
||||
pool!.Add(entity, component);
|
||||
_world.ComponentStorage.GetOrCreateMask(typeHandle).SetBit(entity.ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a component of type <typeparamref name="T"/> to the given <see cref="Entity"/>.
|
||||
/// </summary>
|
||||
@@ -100,7 +112,6 @@ public struct EntityManager : IDisposable
|
||||
{
|
||||
_world.ComponentStorage.GetOrCreateComponentPool<T>().Add(entity, component);
|
||||
_world.ComponentStorage.GetOrCreateMask(TypeHandle.Get<T>()).SetBit(entity.ID);
|
||||
OnComponentAdded?.Invoke(entity, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -123,7 +134,6 @@ public struct EntityManager : IDisposable
|
||||
}
|
||||
|
||||
_world.ComponentStorage.GetOrCreateMask(TypeHandle.Get<T>()).ClearBit(entity.ID);
|
||||
OnComponentRemoved?.Invoke(entity, typeof(T));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -183,7 +193,6 @@ public struct EntityManager : IDisposable
|
||||
where T : ScriptComponent, new()
|
||||
{
|
||||
_world.ComponentStorage.ScriptComponentPool.Add(entity, new T());
|
||||
OnComponentAdded?.Invoke(entity, typeof(ScriptComponent));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -203,9 +212,14 @@ public struct EntityManager : IDisposable
|
||||
|
||||
var instance = (ScriptComponent?)Activator.CreateInstance(type) ?? throw new InvalidOperationException($"Failed to create instance of {type}.");
|
||||
_world.ComponentStorage.ScriptComponentPool.Add(entity, instance);
|
||||
OnComponentAdded?.Invoke(entity, typeof(ScriptComponent));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a script of type <typeparamref name="T"/> from the given <see cref="Entity"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the script to remove.</typeparam>
|
||||
/// <param name="entity">The entity from which the script is to be removed.</param>
|
||||
/// <returns>True if the script was successfully removed; otherwise, false.</returns>
|
||||
public readonly bool RemoveScript<T>(Entity entity)
|
||||
where T : ScriptComponent
|
||||
{
|
||||
@@ -214,10 +228,15 @@ public struct EntityManager : IDisposable
|
||||
return false;
|
||||
}
|
||||
|
||||
OnComponentRemoved?.Invoke(entity, typeof(ScriptComponent));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a script at the specified index from the given <see cref="Entity"/>.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity from which the script is to be removed.</param>
|
||||
/// <param name="index">The index of the script to remove.</param>
|
||||
/// <returns>True if the script was successfully removed; otherwise, false.</returns>
|
||||
public readonly bool RemoveScriptAt(Entity entity, int index)
|
||||
{
|
||||
if (!_world.ComponentStorage.ScriptComponentPool.RemoveAt(entity, index))
|
||||
@@ -225,7 +244,6 @@ public struct EntityManager : IDisposable
|
||||
return false;
|
||||
}
|
||||
|
||||
OnComponentRemoved?.Invoke(entity, typeof(ScriptComponent));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -238,7 +256,7 @@ public struct EntityManager : IDisposable
|
||||
public readonly T? GetScript<T>(Entity entity)
|
||||
where T : ScriptComponent
|
||||
{
|
||||
return (T?)_world.ComponentStorage.ScriptComponentPool.Get(entity)?
|
||||
return (T?)_world.ComponentStorage.ScriptComponentPool.GetAll(entity)?
|
||||
.FirstOrDefault(script => script is T tScript);
|
||||
}
|
||||
|
||||
@@ -251,7 +269,7 @@ public struct EntityManager : IDisposable
|
||||
public readonly IEnumerable<T> GetScripts<T>(Entity entity)
|
||||
where T : ScriptComponent
|
||||
{
|
||||
return (IEnumerable<T>?)_world.ComponentStorage.ScriptComponentPool.Get(entity)?.Where(script => script is T tScript) ?? Enumerable.Empty<T>();
|
||||
return (IEnumerable<T>?)_world.ComponentStorage.ScriptComponentPool.GetAll(entity)?.Where(script => script is T tScript) ?? Enumerable.Empty<T>();
|
||||
}
|
||||
|
||||
public readonly void Dispose()
|
||||
|
||||
Reference in New Issue
Block a user