You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Babushka/scripts/CSharp/GameEntity/Management/EntityManager.cs

157 lines
5.2 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using Babushka.scripts.CSharp.GameEntity.Entities;
using Godot;
using Newtonsoft.Json.Linq;
using Entity = Babushka.scripts.CSharp.GameEntity.Entities.Entity;
using PositionalEntity = Babushka.scripts.CSharp.GameEntity.Entities.PositionalEntity;
namespace Babushka.scripts.CSharp.GameEntity.Management;
/// <summary>
/// Manages the lifecycle and interactions of all entities within the game, including their creation, retrieval,
/// and organization. The EntityManager serves as a centralized hub for managing both standard and positional entities.
/// </summary>
public partial class EntityManager : Node
{
public static EntityManager Instance;
[Export] private EntityNodeCreator _nodeCreator = null!;
[Export] private string saveDirectory = "user://save_data/";
private EntitySceneContainer? _currentEntitySceneContainer;
private readonly List<Entity> _allEntities = new();
public IEnumerable<Entity> AllEntities => _allEntities;
public IEnumerable<PositionalEntity> AllPositionalEntities => _allEntities.OfType<PositionalEntity>();
public EntitySceneContainer? CurrentEntitySceneContainer => _currentEntitySceneContainer;
public EntityNodeCreator NodeCreator => _nodeCreator;
public override void _EnterTree()
{
Instance = this;
Load();
}
public override void _Input(InputEvent @event)
{
// for debugging purposes
if (@event.IsActionPressed("DebugEntities"))
{
GD.Print("Entities:");
foreach (var entity in AllEntities)
{
GD.Print(entity.EntityType + " " + entity.id);
}
}
if(@event.IsActionPressed("SaveGame")) Save();
}
public void Save()
{
JArray array = new JArray();
foreach (var entity in AllEntities)
{
JObject saveData = new JObject();
entity.SaveEntity(saveData);
array.Add(saveData);
}
using var SaveFile = FileAccess.Open(saveDirectory + "save.json", FileAccess.ModeFlags.Write);
SaveFile.StoreString(array.ToString());
}
public void Load()
{
using var saveFile = FileAccess.Open(saveDirectory + "save.json", FileAccess.ModeFlags.Read);
if (saveFile == null) return;
JArray array = JArray.Parse(saveFile.GetAsText());
foreach (var token in array)
{
var jobj = (JObject)token;
if (jobj == null) continue;
if (jobj.TryGetValue("type", out var entityType))
{
string entityTypeString = (string) entityType!;
Entity entity = InitializeEntity(entityTypeString);
entity.LoadEntity(jobj);
AddEntity(entity);
}
}
}
private Entity InitializeEntity(string type)
{
Entity entity = type switch
{
TrashEntity.OWN_TYPE_NAME => new TrashEntity(),
LoadedScenesEntity.OWN_TYPE_NAME => new LoadedScenesEntity(),
_ => throw new Exception($"Trying to load unknown entity type: {type}")
};
return entity;
}
#region ENTITY MANAGEMENT
/// <summary>
/// Adds an entity to the list of managed entities. If the entity is a positional entity
/// and its scene matches the current scene container, it is also instantiated in the scene.
/// </summary>
/// <param name="entity">The entity to be added to the manager.</param>
public void AddEntity(Entity entity)
{
if (!_allEntities.Contains(entity))
_allEntities.Add(entity);
if(entity is PositionalEntity positionalEntity && positionalEntity.sceneName == _currentEntitySceneContainer?.sceneName)
InstantiatePositionalEntityNode(positionalEntity);
}
private void InstantiatePositionalEntityNode(PositionalEntity entity)
{
if(_currentEntitySceneContainer == null) return;
entity.InstantiateEntityNode(_currentEntitySceneContainer);
}
/// <summary>
/// Retrieves the first entity of the specified type from the list of managed entities.
/// If no such entity exists, creates a new instance of the specified type, adds it to the manager, and returns it.
/// </summary>
/// <typeparam name="T">The type of entity to retrieve or create. Must inherit from the Entity class and have a parameterless constructor.</typeparam>
/// <returns>The first entity of the specified type or a newly created entity of that type if none were found.</returns>
public T GetUniqueEntity<T>() where T : Entity, new()
{
var result = AllEntities.OfType<T>().FirstOrDefault();
if (result == null)
{
var newEntity = new T();
AddEntity(newEntity);
result = newEntity;
}
return result;
}
#endregion
#region SCENE CONTAINER ACCESS
public void SetSceneContainer(EntitySceneContainer sceneContainer)
{
_currentEntitySceneContainer = sceneContainer;
}
public void UnsetSceneContainer()
{
_currentEntitySceneContainer = null;
}
#endregion
}