using GatherAndDefend.LevelEditor; using System.Collections.Generic; using System.Text; using UnityEngine.Tilemaps; using UnityEngine; using System.Linq; using Newtonsoft.Json; using System.IO; /// /// data class for containing everything level related /// public class LevelManager : Singleton { string SavePath => Application.dataPath + "/save.txt"; public event OnLevelLoaded LevelLoaded; public delegate void OnLevelLoaded(Level level); public delegate void LevelAction(ILevelObject levelObject); public delegate bool LevelPredicate(T levelObject) where T : ILevelObject; private readonly List _toAdd; private readonly List _toRemove; private readonly List _levelObjects; private Tilemap _dynamicTilemap; public Tilemap DynamicTilemap { get { if (!_dynamicTilemap) { var grid = Object.FindObjectOfType(); _dynamicTilemap = new GameObject("Dynamic").AddComponent(); _dynamicTilemap.gameObject.AddComponent().sortingOrder = 3; _dynamicTilemap.transform.SetParent(grid.transform); _dynamicTilemap.tileAnchor = Vector3.zero; } return _dynamicTilemap; } } private Level _currentLevel; public Level CurrentLevel => _currentLevel; public Transform LevelTransform { get; set; } public LevelManager() { _toAdd = new List(); _toRemove = new List(); _levelObjects = new List(); } #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(_toAdd); toAdd.ForEach(addedObject => { _toAdd.Remove(addedObject); _levelObjects.Add(addedObject); addedObject.LevelStart(); }); var toRemove = new List(_toRemove); toRemove.ForEach(removedObject => { _toRemove.Remove(removedObject); _levelObjects.Remove(removedObject); removedObject.LevelDestroy(); }); toRemove.Clear(); } public void ClearLevel() { foreach (var obj in _levelObjects) { obj.RemoveFromLevel(); } Clear(); } /// /// permet de loader un scriptable object de niveau /// /// le niveau à loader /// est ce qu'on veut effacer ce qui est déjà là? public void LoadLevel(Level level, bool shouldClear = false) { if (shouldClear) { ClearLevel(); } _currentLevel = 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.tileAnchor = Vector3.zero; tilemap.gameObject.AddComponent(); tilemapData.LoadToTilemap(tilemap); tilemap.transform.SetParent(grid.transform); } LevelLoaded?.Invoke(level); Debug.Log("level loaded successfully"); } /// /// permet de loader un scriptable object de niveau /// /// le nom du niveau à loader /// est ce qu'on veut effacer ce qui est déjà là? public void LoadLevel(string levelName, bool shouldClear = false) { if (shouldClear) { ClearLevel(); } //fetch level from database _currentLevel = Database.Instance.ScriptableObjects[levelName] as Level; LoadLevel(_currentLevel, shouldClear); } public void SaveFile() { var list = _levelObjects.Select(obj => obj.ToDictionary()).ToList(); foreach (var tilemapData in _currentLevel) { var levelConfig = tilemapData.ToDictionary(); levelConfig[nameof(ILevelObject.ObjectType)] = nameof(ILevelObject.ObjectType.Tilemap); list.Add(levelConfig); } list.Add(OtherValuesToDict()); string saved = JsonConvert.SerializeObject(list); File.WriteAllText(SavePath, saved, Encoding.UTF8); Debug.Log("game saved successfully"); } public void LoadFile() { string saved = File.ReadAllText(SavePath, Encoding.UTF8); var dicts = JsonConvert.DeserializeObject>>(saved); ClearLevel(); var tilemapDicts = dicts.FindAll(x => x[nameof(ILevelObject.ObjectType)].ToString() == nameof(ILevelObject.ObjectType.Tilemap)); foreach (var tilemapDict in tilemapDicts) CreateTilemap(tilemapDict); var prefabDicts = dicts.FindAll(x => x[nameof(ILevelObject.ObjectType)].ToString() == nameof(ILevelObject.ObjectType.Prefab)); foreach (var prefabDict in prefabDicts) CreatePrefab(prefabDict); var tileDicts = dicts.FindAll(x => x[nameof(ILevelObject.ObjectType)].ToString() == nameof(ILevelObject.ObjectType.Tile)); foreach (var tileDict in tileDicts) CreateTile(tileDict); var otherDict = dicts.Find(x => x[nameof(ILevelObject.ObjectType)].ToString() == nameof(ILevelObject.ObjectType.Other)); DictToOtherValues(otherDict); LevelLoaded?.Invoke(_currentLevel); Debug.Log("game loaded successfully"); } private void CreatePrefab(Dictionary dict) { var name = dict["Name"].ToString(); var prefab = Database.Instance.Prefabs[name]; var instance = prefab.Create(Vector3.zero, parent: LevelTransform); var comp = instance.GetComponent(); comp.LoadDictionary(dict); } private void CreateTile(Dictionary dict) { var name = dict["Name"].ToString(); var tile = Object.Instantiate(Database.Instance.ScriptableObjects[name]) as LevelTile; tile.Instantiated = true; tile.LoadDictionary(dict); tile.AddToLevel(); } private void CreateTilemap(Dictionary dict) { TilemapData.FromDictionary(dict); } private Dictionary OtherValuesToDict() { return new Dictionary() { [nameof(ILevelObject.ObjectType)] = nameof(ILevelObject.ObjectType.Other), [nameof(_currentLevel)] = _currentLevel.name }; } private void DictToOtherValues(Dictionary dict) { // fetch current level var levelName = dict[nameof(_currentLevel)].ToString(); var level = Database.Instance.ScriptableObjects[levelName] as Level; _currentLevel = level; } /// /// align camera to the rightmost tile of the tilemap /// #endregion }