diff --git a/Babushka.csproj b/Babushka.csproj
index e6eea3b..8ad7a50 100644
--- a/Babushka.csproj
+++ b/Babushka.csproj
@@ -8,4 +8,7 @@
+
+
+
\ No newline at end of file
diff --git a/scripts/CSharp/GameEntity/Entities/Entity.cs b/scripts/CSharp/GameEntity/Entities/Entity.cs
new file mode 100644
index 0000000..1661fe4
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Entities/Entity.cs
@@ -0,0 +1,23 @@
+using Babushka.scripts.CSharp.GameEntity.LoadSave;
+using Babushka.scripts.CSharp.GameEntity.Types;
+using Godot;
+using Newtonsoft.Json.Linq;
+
+namespace Babushka.scripts.CSharp.GameEntity.Entities;
+
+public partial class Entity : Node2D
+{
+ private long _id;
+ protected virtual EntityType Type => EntityType.None;
+
+ protected virtual void SaveEntity(JObject json)
+ {
+ json["id"] = _id;
+ json["type"] = (int)Type;
+ }
+
+ protected virtual void LoadEntity(JObject json)
+ {
+ _id = json.GetLongValue("id");
+ }
+}
\ No newline at end of file
diff --git a/scripts/CSharp/GameEntity/Entities/Entity.cs.uid b/scripts/CSharp/GameEntity/Entities/Entity.cs.uid
new file mode 100644
index 0000000..ba72fbb
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Entities/Entity.cs.uid
@@ -0,0 +1 @@
+uid://hnmpt23ovfgl
diff --git a/scripts/CSharp/GameEntity/Entities/PositionalEntity.cs b/scripts/CSharp/GameEntity/Entities/PositionalEntity.cs
new file mode 100644
index 0000000..232f1b6
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Entities/PositionalEntity.cs
@@ -0,0 +1,27 @@
+using Babushka.scripts.CSharp.GameEntity.LoadSave;
+using Godot;
+using Newtonsoft.Json.Linq;
+
+namespace Babushka.scripts.CSharp.GameEntity.Entities;
+
+public partial class PositionalEntity : Entity
+{
+ public string sceneName = "none";
+
+ protected override void SaveEntity(JObject json)
+ {
+ base.SaveEntity(json);
+ json["posx"] = Position.X;
+ json["posy"] = Position.Y;
+ json["scene"] = sceneName;
+ }
+
+ protected override void LoadEntity(JObject json)
+ {
+ base.LoadEntity(json);
+ Position = new Vector2(
+ json.GetFloatValue("posx"),
+ json.GetFloatValue("posy"));
+ sceneName = json.GetStringValue("scene");
+ }
+}
\ No newline at end of file
diff --git a/scripts/CSharp/GameEntity/Entities/PositionalEntity.cs.uid b/scripts/CSharp/GameEntity/Entities/PositionalEntity.cs.uid
new file mode 100644
index 0000000..3e9ed4a
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Entities/PositionalEntity.cs.uid
@@ -0,0 +1 @@
+uid://bs38dulqv7sop
diff --git a/scripts/CSharp/GameEntity/LoadSave/EntityLoadSaveUtil.cs b/scripts/CSharp/GameEntity/LoadSave/EntityLoadSaveUtil.cs
new file mode 100644
index 0000000..04750b7
--- /dev/null
+++ b/scripts/CSharp/GameEntity/LoadSave/EntityLoadSaveUtil.cs
@@ -0,0 +1,32 @@
+using Newtonsoft.Json.Linq;
+
+namespace Babushka.scripts.CSharp.GameEntity.LoadSave;
+
+public static class EntityLoadSaveUtil
+{
+ private static void AssertTokenType(this JObject json, string key, JTokenType type)
+ {
+ var token = json[key];
+ if (token == null) throw new MalformedJsonException(json, key, "does not exist");
+ if (!token.HasValues) throw new MalformedJsonException(json, key, "has no value");
+ if (token.Type != type) throw new MalformedJsonException(json, key, $"is not of type {type}");
+ }
+
+ public static long GetLongValue(this JObject json, string key)
+ {
+ AssertTokenType(json, key, JTokenType.Integer);
+ return json.Value(key);
+ }
+
+ public static float GetFloatValue(this JObject json, string key)
+ {
+ AssertTokenType(json, key, JTokenType.Float);
+ return json.Value(key);
+ }
+
+ public static string GetStringValue(this JObject json, string key)
+ {
+ AssertTokenType(json, key, JTokenType.String);
+ return json.Value(key)!;
+ }
+}
\ No newline at end of file
diff --git a/scripts/CSharp/GameEntity/LoadSave/EntityLoadSaveUtil.cs.uid b/scripts/CSharp/GameEntity/LoadSave/EntityLoadSaveUtil.cs.uid
new file mode 100644
index 0000000..350cb0f
--- /dev/null
+++ b/scripts/CSharp/GameEntity/LoadSave/EntityLoadSaveUtil.cs.uid
@@ -0,0 +1 @@
+uid://ccu6p418viliu
diff --git a/scripts/CSharp/GameEntity/LoadSave/MalformedJsonException.cs b/scripts/CSharp/GameEntity/LoadSave/MalformedJsonException.cs
new file mode 100644
index 0000000..d04f379
--- /dev/null
+++ b/scripts/CSharp/GameEntity/LoadSave/MalformedJsonException.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using Newtonsoft.Json.Linq;
+
+namespace Babushka.scripts.CSharp.GameEntity.LoadSave;
+
+public class MalformedJsonException(JObject actualJson, string key, string problem) : Exception
+{
+ public override string Message => $"JsonObject was malformed: {key} {problem}";
+ public override IDictionary Data => new Dictionary { { "json", actualJson } };
+}
\ No newline at end of file
diff --git a/scripts/CSharp/GameEntity/LoadSave/MalformedJsonException.cs.uid b/scripts/CSharp/GameEntity/LoadSave/MalformedJsonException.cs.uid
new file mode 100644
index 0000000..76f73aa
--- /dev/null
+++ b/scripts/CSharp/GameEntity/LoadSave/MalformedJsonException.cs.uid
@@ -0,0 +1 @@
+uid://d1o066hh84ow
diff --git a/scripts/CSharp/GameEntity/Management/EntityManager.cs b/scripts/CSharp/GameEntity/Management/EntityManager.cs
new file mode 100644
index 0000000..7525268
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Management/EntityManager.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Babushka.scripts.CSharp.GameEntity.Types;
+using Godot;
+using Entity = Babushka.scripts.CSharp.GameEntity.Entities.Entity;
+using PositionalEntity = Babushka.scripts.CSharp.GameEntity.Entities.PositionalEntity;
+
+namespace Babushka.scripts.CSharp.GameEntity.Management;
+
+public partial class EntityManager : Node
+{
+ [Export] private EntityNodeCreator _nodeCreator = null!;
+
+ private EntitySceneManager? _currentEntitySceneManager;
+
+
+ private readonly List _allEntities = new();
+
+ public IEnumerable AllEntities => _allEntities;
+
+ public IEnumerable AllPositionalEntities => _allEntities.OfType();
+
+ public T NewPositionalEntity(EntityType type, Vector2 position, string? scene = null) where T : PositionalEntity
+ {
+ if (scene == null)
+ {
+ if (_currentEntitySceneManager == null)
+ throw new Exception("No current scene. Specify scene to spawn an entity");
+
+ scene = _currentEntitySceneManager.sceneName;
+ }
+
+ var newEntity = _nodeCreator.Create(type);
+ newEntity.Position = position;
+ newEntity.sceneName = scene;
+ _allEntities.Add(newEntity);
+
+ _currentEntitySceneManager.AddIfNeeded(newEntity);
+
+ return newEntity;
+ }
+
+ public void UnloadScene()
+ {
+ if (_currentEntitySceneManager == null) return;
+ _currentEntitySceneManager.RemoveAllEntities();
+ _currentEntitySceneManager = null;
+ }
+
+ public void LoadScene(EntitySceneManager sceneManager)
+ {
+ _currentEntitySceneManager = sceneManager;
+ foreach (var entity in AllPositionalEntities)
+ {
+ _currentEntitySceneManager.AddIfNeeded(entity);
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/CSharp/GameEntity/Management/EntityManager.cs.uid b/scripts/CSharp/GameEntity/Management/EntityManager.cs.uid
new file mode 100644
index 0000000..4f201fd
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Management/EntityManager.cs.uid
@@ -0,0 +1 @@
+uid://umop2b1m1qm8
diff --git a/scripts/CSharp/GameEntity/Management/EntityManagerUtil.cs b/scripts/CSharp/GameEntity/Management/EntityManagerUtil.cs
new file mode 100644
index 0000000..4b58348
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Management/EntityManagerUtil.cs
@@ -0,0 +1,14 @@
+using PositionalEntity = Babushka.scripts.CSharp.GameEntity.Entities.PositionalEntity;
+
+namespace Babushka.scripts.CSharp.GameEntity.Management;
+
+public static class EntityManagerUtil
+{
+ public static void AddIfNeeded(this EntitySceneManager? self, PositionalEntity entity)
+ {
+ if(self == null) return;
+ if(self.sceneName != entity.sceneName) return;
+
+ self.AddEntity(entity);
+ }
+}
\ No newline at end of file
diff --git a/scripts/CSharp/GameEntity/Management/EntityManagerUtil.cs.uid b/scripts/CSharp/GameEntity/Management/EntityManagerUtil.cs.uid
new file mode 100644
index 0000000..1fbbf02
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Management/EntityManagerUtil.cs.uid
@@ -0,0 +1 @@
+uid://dc3283h7sx4cl
diff --git a/scripts/CSharp/GameEntity/Management/EntityNodeCreator.cs b/scripts/CSharp/GameEntity/Management/EntityNodeCreator.cs
new file mode 100644
index 0000000..f763b15
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Management/EntityNodeCreator.cs
@@ -0,0 +1,16 @@
+using Babushka.scripts.CSharp.GameEntity.Types;
+using Godot;
+using Godot.Collections;
+using Entity = Babushka.scripts.CSharp.GameEntity.Entities.Entity;
+
+namespace Babushka.scripts.CSharp.GameEntity.Management;
+
+public partial class EntityNodeCreator : Node
+{
+ [Export] private Dictionary _entityPrefabs;
+
+ public T Create(EntityType type) where T:Entity
+ {
+ return _entityPrefabs[type].Instantiate();
+ }
+}
\ No newline at end of file
diff --git a/scripts/CSharp/GameEntity/Management/EntityNodeCreator.cs.uid b/scripts/CSharp/GameEntity/Management/EntityNodeCreator.cs.uid
new file mode 100644
index 0000000..dec3ecb
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Management/EntityNodeCreator.cs.uid
@@ -0,0 +1 @@
+uid://bogqp274y1pgr
diff --git a/scripts/CSharp/GameEntity/Management/EntitySceneManager.cs b/scripts/CSharp/GameEntity/Management/EntitySceneManager.cs
new file mode 100644
index 0000000..2d7e838
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Management/EntitySceneManager.cs
@@ -0,0 +1,25 @@
+using Godot;
+using PositionalEntity = Babushka.scripts.CSharp.GameEntity.Entities.PositionalEntity;
+
+namespace Babushka.scripts.CSharp.GameEntity.Management;
+
+public partial class EntitySceneManager : Node2D
+{
+ [Export] public string sceneName = "none";
+
+ public void AddEntity(PositionalEntity entity)
+ {
+ AddChild(entity);
+ }
+
+ public void RemoveAllEntities()
+ {
+ foreach (var entity in GetChildren())
+ {
+ if (entity is PositionalEntity positionalEntity)
+ {
+ RemoveChild(entity);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/CSharp/GameEntity/Management/EntitySceneManager.cs.uid b/scripts/CSharp/GameEntity/Management/EntitySceneManager.cs.uid
new file mode 100644
index 0000000..12921a3
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Management/EntitySceneManager.cs.uid
@@ -0,0 +1 @@
+uid://ca1pg6k3gn47y
diff --git a/scripts/CSharp/GameEntity/Types/EntityType.cs b/scripts/CSharp/GameEntity/Types/EntityType.cs
new file mode 100644
index 0000000..92be4a5
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Types/EntityType.cs
@@ -0,0 +1,7 @@
+namespace Babushka.scripts.CSharp.GameEntity.Types;
+
+public enum EntityType
+{
+ None = 0,
+ Yeli = 1,
+}
\ No newline at end of file
diff --git a/scripts/CSharp/GameEntity/Types/EntityType.cs.uid b/scripts/CSharp/GameEntity/Types/EntityType.cs.uid
new file mode 100644
index 0000000..f548051
--- /dev/null
+++ b/scripts/CSharp/GameEntity/Types/EntityType.cs.uid
@@ -0,0 +1 @@
+uid://cjygyr4lc224m