130 lines
3.9 KiB
C#
130 lines
3.9 KiB
C#
using GameCore.Config;
|
|
using GameCore.ECS.Interfaces;
|
|
using GameCore.Events;
|
|
using GameCore.Events.Interfaces;
|
|
using GameCore.Input.Interfaces;
|
|
using GameCore.Interaction;
|
|
using GameCore.Logging.Interfaces;
|
|
|
|
namespace GameCore.ECS;
|
|
|
|
/// <summary>
|
|
/// The central container for the entire game state.
|
|
/// It manages all entities, components, and systems, and orchestrates the main game loop.
|
|
/// This class is the primary point of interaction for the Engine/Presentation layer.
|
|
/// </summary>
|
|
public class World(IInputService inputService, IWorldQuery worldQuery, SimulationConfig config, ILogger logger)
|
|
{
|
|
private readonly Dictionary<int, List<IComponent>> _componentsByEntityId = new();
|
|
private readonly EventBus _eventBus = new();
|
|
private readonly List<ISystem> _systems = [];
|
|
|
|
public readonly SimulationConfig Config = config;
|
|
public readonly IInputService InputService = inputService;
|
|
public readonly ILogger Logger = logger;
|
|
public readonly IWorldQuery WorldQuery = worldQuery;
|
|
private int _nextEntityId;
|
|
|
|
/// <summary>
|
|
/// Creates a new, unique entity.
|
|
/// </summary>
|
|
/// <returns>The newly created Entity.</returns>
|
|
public Entity CreateEntity()
|
|
{
|
|
var id = _nextEntityId++;
|
|
_componentsByEntityId[id] = [];
|
|
return new Entity(id);
|
|
}
|
|
|
|
public void DestroyEntity(Entity entity)
|
|
{
|
|
_componentsByEntityId.Remove(entity.Id);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a component to a given entity.
|
|
/// </summary>
|
|
public void AddComponent(Entity entity, IComponent component)
|
|
{
|
|
_componentsByEntityId[entity.Id].Add(component);
|
|
}
|
|
|
|
public void RemoveComponent<T>(Entity entity) where T : class, IComponent
|
|
{
|
|
if (!_componentsByEntityId.TryGetValue(entity.Id, out var components)) return;
|
|
|
|
var componentToRemove = components.OfType<T>().FirstOrDefault();
|
|
if (componentToRemove != null) components.Remove(componentToRemove);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves a specific type of component from an entity.
|
|
/// </summary>
|
|
/// <returns>The component instance, or null if the entity doesn't have it.</returns>
|
|
public T? GetComponent<T>(Entity entity) where T : class, IComponent
|
|
{
|
|
return _componentsByEntityId.TryGetValue(entity.Id, out var components)
|
|
? components.OfType<T>().FirstOrDefault()
|
|
: null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds all entities that have a specific component type.
|
|
/// </summary>
|
|
public IEnumerable<Entity> GetEntitiesWith<T>() where T : IComponent
|
|
{
|
|
return from pair in _componentsByEntityId
|
|
where pair.Value.Any(c => c is T)
|
|
select new Entity(pair.Key);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers a system to be run in the game loop.
|
|
/// </summary>
|
|
public void RegisterSystem(ISystem system)
|
|
{
|
|
_systems.Add(system);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Runs a single tick of the game simulation, updating all registered systems.
|
|
/// </summary>
|
|
public void Update(float deltaTime)
|
|
{
|
|
foreach (var system in _systems) system.Update(this, deltaTime);
|
|
}
|
|
|
|
public void PublishEvent(IEvent gameEvent)
|
|
{
|
|
_eventBus.Publish(gameEvent);
|
|
}
|
|
|
|
public void ProcessEvents()
|
|
{
|
|
_eventBus.ProcessEvents();
|
|
}
|
|
|
|
public void Subscribe<T>(Action<T> handler) where T : IEvent
|
|
{
|
|
_eventBus.Subscribe(handler);
|
|
}
|
|
|
|
public void Unsubscribe<T>(Action<T> handler) where T : IEvent
|
|
{
|
|
_eventBus.Unsubscribe(handler);
|
|
}
|
|
|
|
public Entity? FindEntityByWorldId(string worldId)
|
|
{
|
|
if (string.IsNullOrEmpty(worldId)) return null;
|
|
|
|
foreach (var entity in _componentsByEntityId.Keys.Select(id => new Entity(id)))
|
|
{
|
|
var idComponent = GetComponent<WorldIdComponent>(entity);
|
|
if (idComponent != null && idComponent.WorldId == worldId)
|
|
return entity;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
} |