Browse Source

refactored game modules interface

James Peret 2 years ago
parent
commit
05f7ecd002

+ 72 - 3
Runtime/ModuleSystem/GameConfig.cs

@@ -1,17 +1,20 @@
-using System.Collections;
+using System;
+using System.Linq;
+using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using Sirenix.OdinInspector;
 using KairoEngine.Core;
 using KairoEngine.Core.ConfigOptions;
+using UniRx;
 
 namespace KairoEngine.Core.ModuleSystem
 {
     [CreateAssetMenu(fileName = "GameConfig", menuName = "KairoEngine/GameConfig"), HideMonoScript]
-    public class GameConfig : ScriptableObject
+    public class GameConfig : ScriptableObject, ISerializationCallbackReceiver
     {
         [ListDrawerSettings(DraggableItems = false, HideRemoveButton = true, ShowPaging = false)]
-        [OnValueChanged("StartModule")]
+        [ShowInInspector, NonSerialized, OnValueChanged("StartModule"), OnInspectorInit("StartModule")]
         public List<GameModule> modules = new List<GameModule>();
 
         [InlineProperty, HideLabel] public ConfigOptionsManager configOptions = new ConfigOptionsManager();
@@ -27,5 +30,71 @@ namespace KairoEngine.Core.ModuleSystem
                 }
             }
         }
+
+        [OnInspectorInit("GetModuleNames"), OnValueChanged("AddNewModule")]
+        [ValueDropdown("possibleModules", IsUniqueList = false)]
+        [LabelText("Add New Module")]
+        [NonSerialized]
+        public GameModule newModule;
+
+        [NonSerialized] private IEnumerable possibleModules = new ValueDropdownList<GameModule>();
+
+        private void GetModuleNames()
+        {
+            possibleModules = ReflectiveEnumerator.GetEnumerableOfType<GameModule>(this)
+                .Where(x => x.typeName != "GameModule")
+                .Where(x => x.typeName != "GameModuleBase")
+                .Select(x => new ValueDropdownItem(x.name, x));
+        }
+
+        private void AddNewModule()
+        {
+            for (int i = 0; i < modules.Count; i++)
+            {
+                if(modules[i].name == newModule.name) 
+                {
+                    newModule = null;
+                    return;
+                }   
+            }
+            if(newModule != null)
+            {
+                modules.Add(newModule);
+                newModule = null;
+            }
+        }
+
+        [SerializeField, HideInInspector] private List<string> serializedModules = new List<string>();
+        [SerializeField, HideInInspector] private ObjectSerializer serializer = new ObjectSerializer();
+
+        public void OnBeforeSerialize()
+        {
+            if(modules == null) return;
+            serializedModules = new List<string>();
+            serializer.Clear();
+            for (int i = 0; i < modules.Count; i++)
+            {
+                modules[i].OnBeforeSerialize(serializer);
+                string data = JsonUtility.ToJson(modules[i]);
+                serializedModules.Add(data);
+            }
+        }
+
+        public void OnAfterDeserialize()
+        {
+            if(serializedModules == null) return;
+            if(modules == null) modules = new List<GameModule>();
+            if(modules.Count > 0) modules.Clear();
+            for (int i = 0; i < serializedModules.Count; i++)
+            {
+                GameModule module = JsonUtility.FromJson<GameModuleBase>(serializedModules[i]);
+                module = GameModule.InvokeStringMethod(module.className, module.typeName, serializedModules[i]);
+                module.gameConfig = this;
+                module.OnBeforeDeserialize(serializer);
+                modules.Add(module);
+            }
+            serializer.Clear();
+        }
+
     }
 }

+ 2 - 2
Runtime/ModuleSystem/GameInstaller.cs

@@ -17,7 +17,7 @@ namespace KairoEngine.Core.ModuleSystem
             //Container.Bind<ICursorRules>().To<SneakyCursorRules>().AsSingle();
             for (int i = 0; i < gameConfig.modules.Count; i++)
             {
-                if(gameConfig.modules[i].enableModule) gameConfig.modules[i].module.Load(this.transform);
+                if(gameConfig.modules[i].enableModule) gameConfig.modules[i].Load(this.transform);
             }
         }
 
@@ -36,7 +36,7 @@ namespace KairoEngine.Core.ModuleSystem
             {
                 if(gameConfig.modules[i].enableModule) 
                 {
-                    gameConfig.modules[i].module.Destroy();
+                    gameConfig.modules[i].Destroy();
                     c += 1;
                 }
             }

+ 70 - 17
Runtime/ModuleSystem/GameModule.cs

@@ -1,39 +1,92 @@
-using System.Collections;
+
+using System;
+using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using Sirenix.OdinInspector;
 
 namespace KairoEngine.Core.ModuleSystem
 {
-    [System.Serializable]
-    public class GameModule
+    [System.Serializable, HideReferenceObjectPicker]
+    public class GameModule : IComparable<GameModule>
     {
-        [SerializeField, HideInInspector] private string _name = "Empty Module Slot";
+        [SerializeField, HideInInspector] public virtual string name => "Empty Module Slot";
+        [SerializeField, HideInInspector] public string typeName = "GameModule";
+        [SerializeField, HideInInspector] public string className;
 
-        [InlineButton("ResetModule", "Reset")]
-        [InlineButton("RemoveModule", "Remove")]
-        [FoldoutGroup("@_name"), HideIf("@module == null")] public bool enableModule = true;
-
-        [SerializeReference, InlineProperty, HideLabel, FoldoutGroup("@_name"), OnValueChanged("UpdateModuleName"), PropertySpace(SpaceBefore = 5, SpaceAfter = 5)] 
-        public IGameModule module;
+        [InlineButton("Reset", "Reset")]
+        [InlineButton("Remove", "Remove")]
+        [FoldoutGroup("@name")] public bool enableModule = true;
 
         [HideInInspector] public bool isInitialized = false;
         [HideInInspector] public GameConfig gameConfig;
 
-        private void UpdateModuleName()
+        public GameModule(GameConfig config)
+        {
+            this.gameConfig = config;
+            this.className = this.GetType().AssemblyQualifiedName;
+        }
+
+        public virtual void Load(Transform parent)
+        {
+            
+        }
+
+        public virtual void Reset()
         {
-            if(module != null) _name = module.name;
-            else _name = "Empty Module Slot";
+            
         }
-        private void ResetModule()
+
+        public virtual void Destroy()
         {
-            module.Reset();
+            
         }
 
-        [FoldoutGroup("@_name"), HideIf("@module != null"), Button("Remove Empty Module")]
-        private void RemoveModule()
+        [FoldoutGroup("@name")]
+        public virtual void Remove()
         {
             gameConfig.modules.Remove(this);
         }
+
+        public virtual int CompareTo(GameModule other)
+        {
+            if(other == null) return 1;
+            else return -1;
+        }
+
+        public static GameModuleBase InvokeStringMethod(string typeName, string methodName, string data)
+        {
+            Type calledType = Type.GetType(typeName);
+            if(calledType == null)
+            {
+                Debug.LogError($"Could not find type: \"{typeName}\"");
+                return null;
+            }
+            GameModuleBase module = (GameModuleBase)calledType.InvokeMember($"JSONTo{methodName}", 
+                System.Reflection.BindingFlags.InvokeMethod | 
+                System.Reflection.BindingFlags.Public |
+                System.Reflection.BindingFlags.Static, 
+                null, null, new object[] { data });
+            return module;
+        }
+
+        public static GameModule JSONToGameModule(string data)
+        {
+            return JsonUtility.FromJson<GameModule>(data);
+        }
+
+        public virtual void OnBeforeSerialize(ObjectSerializer serializer) { }
+        public virtual void OnBeforeDeserialize(ObjectSerializer serializer) { }
+    }
+
+    [System.Serializable, HideReferenceObjectPicker]
+    public class GameModuleBase : GameModule
+    {
+        public GameModuleBase(GameConfig config) : base(config) 
+        {
+            this.gameConfig = config;
+            this.className = this.GetType().AssemblyQualifiedName;
+            this.typeName = "GameModuleBase";
+        }
     }
 }

+ 1 - 0
Runtime/ModuleSystem/IGameModule.cs

@@ -13,6 +13,7 @@ namespace KairoEngine.Core.ModuleSystem
         void Reset();
 
         void Destroy();
+
     }
 }
 

+ 24 - 0
Runtime/ObjectSerializer.cs

@@ -0,0 +1,24 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace KairoEngine.Core
+{
+    [System.Serializable]
+    public class ObjectSerializer
+    {
+        [SerializeField, HideInInspector] public Dictionary<string, object> objects = new Dictionary<string, object>();
+        [SerializeField, HideInInspector] public Dictionary<string, GameObject> gameObjecs = new Dictionary<string, GameObject>();
+        [SerializeField, HideInInspector] public Dictionary<string, Component> components = new Dictionary<string, Component>();
+        [SerializeField, HideInInspector] public Dictionary<string, ScriptableObject> scriptableObjects = new Dictionary<string, ScriptableObject>();
+
+        public void Clear()
+        {
+            objects.Clear();
+            gameObjecs.Clear();
+            components.Clear();
+            scriptableObjects.Clear();
+        }
+    }
+
+}

+ 11 - 0
Runtime/ObjectSerializer.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f890ae4289b544848b46ea6f15f4554b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: