using System.Collections.Generic; using System.Linq; using Unity.Plastic.Newtonsoft.Json; using UnityEngine; using UnityEngine.Tilemaps; using GatherAndDefend.LevelEditor; #region [custom inspector] #if UNITY_EDITOR using UnityEditor; [CustomEditor(typeof(LevelManagerScript))] public class LevelManagerEditor : Editor { public override void OnInspectorGUI() { DrawDefaultInspector(); if (GUILayout.Button("Save")) { LevelManager.Instance.SaveLevel(); } if (GUILayout.Button("Load")) { LevelManager.Instance.LoadSave(); } } } #endif #endregion #region [singleton level manager] public class LevelManager : Singleton { public delegate void LevelAction(ILevelObject levelObject); public delegate bool LevelPredicate(T levelObject) where T : ILevelObject; public event LevelAction Added; public event LevelAction Removed; private readonly List _toAdd; private readonly List _toRemove; private readonly List _levelObjects; public Level _currentLevel; public Transform LevelTransform { get;private set; } public LevelManager() { _toAdd = new List(); _toRemove = new List(); _levelObjects = new List(); var mgrScript = Object.FindObjectOfType(); if (!mgrScript) mgrScript = new GameObject(nameof(LevelManager)).AddComponent(); LevelTransform = mgrScript.transform; } #region [~CRUD~] public void Add(ILevelObject levelObject) { _toAdd.Add(levelObject); } public void Remove(ILevelObject levelObject) { _toRemove.Add(levelObject); } public void Clear() { _toAdd.Clear(); _toRemove.Clear(); _levelObjects.Clear(); } public T Get(LevelPredicate predicate = null) where T : ILevelObject { if (predicate == null) predicate = (generic) => true; return (T)_levelObjects.Find(levelObject => levelObject is T generic && predicate(generic)); } public List GetAll(LevelPredicate predicate = null) where T : ILevelObject { if (predicate == null) predicate = (generic) => true; List ret = new(); foreach (var levelObject in _levelObjects) if (levelObject is T generic && predicate(generic)) ret.Add(generic); return ret; } public int Count(LevelPredicate predicate = null) where T : ILevelObject { return GetAll(predicate).Count; } public bool Has(LevelPredicate predicate = null) where T : ILevelObject { if (predicate == null) predicate = (generic) => true; return _levelObjects.Exists(levelObject => levelObject is T generic && predicate(generic)); } #endregion #region [Level management] public void UpdateLevel() { _levelObjects.ForEach(levelObject => levelObject.LevelUpdate()); var toAdd = new List(this._toAdd); toAdd.ForEach(addedObject => { this._toAdd.Remove(addedObject); _levelObjects.Add(addedObject); Added?.Invoke(addedObject); addedObject.LevelStart(); }); var toRemove = new List(this._toRemove); toRemove.ForEach(removedObject => { this._toRemove.Remove(removedObject); _levelObjects.Remove(removedObject); Removed?.Invoke(removedObject); removedObject.LevelDestroy(); }); toRemove.Clear(); } private string saved; public void ClearLevel() { foreach (var obj in _levelObjects) { obj.RemoveFromLevel(); } Clear(); } public void SaveLevel() { var list = _levelObjects.Select(obj => obj.ToDictionary()).ToList(); list.Add(new Dictionary() { {Database.TYPE, "Level" }, {"Name", _currentLevel.name } }); saved = JsonConvert.SerializeObject(list); Debug.Log("game saved successfully"); } public void LoadLevel(string levelName, bool clear = false) { if (clear) { ClearLevel(); } //fetch level from database _currentLevel = Database.Instance.ScriptableObjects[levelName] as Level; Grid grid = Object.FindObjectOfType(); //create new grid if there is none if (!grid) { grid = new GameObject("Grid").AddComponent(); } //remove all tilemaps if there is a grid else { foreach (Transform child in grid.transform) { Object.Destroy(child.gameObject); } } //generate all tilemaps foreach (TilemapData tilemapData in _currentLevel) { var tilemap = new GameObject(tilemapData.Key).AddComponent(); tilemap.gameObject.AddComponent(); tilemapData.LoadToTilemap(tilemap); tilemap.transform.SetParent(grid.transform); } Debug.Log("level loaded successfully"); } public void LoadSave() { ClearLevel(); var dicts = JsonConvert.DeserializeObject>>(saved); //instantiate all prefabs foreach (var dict in JsonConvert.DeserializeObject>>(saved)) { switch (dict[Database.TYPE].ToString()) { case nameof(Database.Prefabs): CreatePrefab(dict); break; case nameof(Level): LoadLevel(dict["Name"].ToString()); break; } } Debug.Log("game loaded successfully"); } private void CreatePrefab(Dictionary dict) { var name = dict["Name"].ToString(); var prefab = Database.Instance.Prefabs[name]; var instance = Object.Instantiate(prefab, LevelTransform); var comp = instance.GetComponent(); comp.LoadDictionary(dict); } #endregion } #endregion #region [mono behaviour] public class LevelManagerScript : MonoBehaviour { public Level firstLevel; private static LevelManagerScript _instance; void Awake() { if (!_instance) _instance = this; else Destroy(gameObject); DontDestroyOnLoad(gameObject); LevelManager.Instance.LoadLevel(firstLevel.name, true); } void Update() { LevelManager.Instance.UpdateLevel(); } } #endregion