using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; using Ichni.Editor; using Ichni.RhythmGame; using Ichni.RhythmGame.Beatmap; using UnityEngine; namespace Ichni { public class ProjectManager { public static readonly ES3Settings SaveSettings = new ES3Settings { compressionType = ES3.CompressionType.None, encryptionType = ES3.EncryptionType.None, format = ES3.Format.JSON, }; public static readonly ES3Settings ExportSettings = new ES3Settings { compressionType = ES3.CompressionType.Gzip, encryptionType = ES3.EncryptionType.AES, encryptionPassword = "Soullies515", format = ES3.Format.JSON, }; public SaveManager saveManager; public LoadManager loadManager; public ExportManager exportManager; public BeatmapClipManager beatmapClipManager; public NotePrefabManager notePrefabManager; public AutoSaveManager autoSaveManager; public ProjectManager() { saveManager = new SaveManager(); loadManager = new LoadManager(); exportManager = new ExportManager(); beatmapClipManager = new BeatmapClipManager(); notePrefabManager = new NotePrefabManager(); autoSaveManager = new AutoSaveManager(); } public void GenerateEmptyProject(ProjectInformation_BM projectInfo_BM, SongInformation_BM songInfo_BM) { projectInfo_BM.ExecuteBM(); songInfo_BM.ExecuteBM(); EditorManager.instance.beatmapContainer = new BeatmapContainer(); EditorManager.instance.commandScripts = new CommandScripts(new List()); } } public class ExportManager { public void Export() { string exportPath = Application.streamingAssetsPath + "/Export/" + EditorManager.instance.projectInformation.projectName; string projectInfoPath = exportPath + "/ProjectInfo.bytes"; string songInfoPath = exportPath + "/SongInfo.bytes"; string beatmapPath = exportPath + "/BeatMap.bytes"; string commandScriptsPath = exportPath + "/CommandScripts.bytes"; LogWindow.Log("Start Exporting..."); ExportProjectInfo(projectInfoPath); ExportSongInfo(songInfoPath); ExportBeatMap(beatmapPath); ExportCommandScripts(commandScriptsPath); LogWindow.Log("Export Complete", Color.green); } private void ExportProjectInfo(string exportPath) { EditorManager.instance.projectInformation.SaveBM(); ES3.Save("ProjectInformation", EditorManager.instance.projectInformation.matchedBM as ProjectInformation_BM, exportPath, ProjectManager.ExportSettings); } private void ExportSongInfo(string exportPath) { EditorManager.instance.songInformation.SaveBM(); ES3.Save("SongInformation", EditorManager.instance.songInformation.matchedBM as SongInformation_BM, exportPath, ProjectManager.ExportSettings); } private void ExportBeatMap(string exportPath) { EditorManager.instance.beatmapContainer.SaveBM(); ES3.Save("BeatMap", EditorManager.instance.beatmapContainer.matchedBM as BeatmapContainer_BM, exportPath, ProjectManager.ExportSettings); } private void ExportCommandScripts(string exportPath) { EditorManager.instance.commandScripts.SaveBM(); ES3.Save("CommandScripts", EditorManager.instance.commandScripts.matchedBM as CommandScripts_BM, exportPath, ProjectManager.ExportSettings); } } public class SaveManager { public void Save() { LogWindow.Log("Start Saving..."); SaveProjectInfo(); SaveSongInfo(); SaveBeatMap(); SaveCommandScripts(); LogWindow.Log("Save Complete", Color.green); } private void SaveProjectInfo() { EditorManager.instance.projectInformation.SaveBM(); ES3.Save("ProjectInformation", EditorManager.instance.projectInformation.matchedBM as ProjectInformation_BM, EditorManager.instance.projectInformation.peojectInfoPath, ProjectManager.SaveSettings); } private void SaveSongInfo() { EditorManager.instance.songInformation.SaveBM(); ES3.Save("SongInformation", EditorManager.instance.songInformation.matchedBM as SongInformation_BM, EditorManager.instance.projectInformation.songInfoPath, ProjectManager.SaveSettings); } private void SaveBeatMap() { EditorManager.instance.beatmapContainer.SaveBM(); ES3.Save("BeatMap", EditorManager.instance.beatmapContainer.matchedBM as BeatmapContainer_BM, EditorManager.instance.projectInformation.beatmapPath, ProjectManager.SaveSettings); } private void SaveCommandScripts() { EditorManager.instance.commandScripts.SaveBM(); ES3.Save("CommandScripts", EditorManager.instance.commandScripts.matchedBM as CommandScripts_BM, EditorManager.instance.projectInformation.CommandScriptsPath, ProjectManager.SaveSettings); } } public class LoadManager { public void Load(string projectName) { LoadProjectInfo(projectName); LoadSongInfo(); LoadCommandScripts(); LoadBeatMap(); LogWindow.Log("Load Complete", Color.green); } private void LoadProjectInfo(string projectName) { string projectInfoPath = Application.streamingAssetsPath + "/Projects/" + projectName + "/ProjectInfo.json"; ES3.Load("ProjectInformation", projectInfoPath, ProjectManager.SaveSettings).ExecuteBM(); } private void LoadSongInfo() { ES3.Load("SongInformation", EditorManager.instance.projectInformation.songInfoPath, ProjectManager.SaveSettings).ExecuteBM(); } private void LoadBeatMap() { ES3.Load("BeatMap", EditorManager.instance.projectInformation.beatmapPath, ProjectManager.SaveSettings).ExecuteBM(); } private void LoadCommandScripts() { ES3.Load("CommandScripts", EditorManager.instance.projectInformation.CommandScriptsPath, ProjectManager.SaveSettings).ExecuteBM(); } } public class BeatmapClipManager { public void SaveClip(string clipName) { LogWindow.Log("Start Saving Clip..."); if (EditorManager.instance.operationManager.currentSelectedElements.Count != 1) // TODO: 后续适应多选 { LogWindow.Log("Please select only one Game Element to save the beatmap clip.", Color.red); return; } GameElement selectedElement = EditorManager.instance.operationManager.currentSelectedElements[0]; if (selectedElement is null) { LogWindow.Log("Please select a Game Element to save the beatmap clip.", Color.red); return; } _SaveClip(selectedElement, clipName); LogWindow.Log("Save Clip Complete", Color.green); } public void LoadClip(string clipName) { LogWindow.Log("Start Loading Clip..."); if(!ES3.FileExists(Application.streamingAssetsPath + "/Clips/" + clipName + ".json")) { LogWindow.Log("Clip not found", Color.red); return; } if (EditorManager.instance.operationManager.currentSelectedElements.Count != 1) // TODO: 后续适应多选 { LogWindow.Log("Please select only one Game Element to load the beatmap clip.", Color.red); return; } GameElement selectedElement = EditorManager.instance.operationManager.currentSelectedElements[0]; if (selectedElement is null) { LogWindow.Log("Please select a Game Element to load the beatmap clip.", Color.red); return; } Debug.Log(selectedElement.elementName + " " + selectedElement.elementGuid); _LoadClip(selectedElement, clipName); LogWindow.Log("Load Clip Complete", Color.green); } private void _SaveClip(GameElement element, string clipName) { List clip = new List(); element.GetAllGameElementsFromThis().ForEach(e => { e.SaveBM(); clip.Add(e.matchedBM); e.submoduleList.ForEach(s => { s.SaveBM(); clip.Add(s.matchedBM); }); }); string filePath = Application.streamingAssetsPath + "/Clips/" + clipName + ".json"; ES3.Save("Clip", clip, filePath, ProjectManager.SaveSettings); } private void _LoadClip(GameElement target, string clipName) { string filePath = Application.streamingAssetsPath + "/Clips/" + clipName + ".json"; List clip = ES3.Load>("Clip", filePath, ProjectManager.SaveSettings); //对于第一个元素,需要特殊处理,将它放入目标物体的子物体列表中 GameElement_BM first = clip[0] as GameElement_BM; List firstAttaches = GameElement_BM.GetAllAttachedBaseElements(first, clip); first.elementGuid = Guid.NewGuid(); GameElement_BM.identifier.TryAdd(first.elementGuid, first); firstAttaches.ForEach(e => { e.attachedElementGuid = first.elementGuid; }); //将目标物体(临时)存入读存档的Dictionary中 target.SaveBM(); GameElement_BM.identifier.TryAdd(target.elementGuid, target.matchedBM as GameElement_BM); (target.matchedBM as GameElement_BM).matchedElement = target; first.attachedElementGuid = target.elementGuid; for (var index = 1; index < clip.Count; index++) { var element = clip[index]; if (element is GameElement_BM gameElement) { List attachedElements = GameElement_BM.GetAllAttachedBaseElements(gameElement, clip); gameElement.elementGuid = Guid.NewGuid(); GameElement_BM.identifier.TryAdd(gameElement.elementGuid, gameElement); attachedElements.ForEach(e => { e.attachedElementGuid = gameElement.elementGuid; }); } } first.ExecuteBM(); for (var index = 1; index < clip.Count; index++) { clip[index].ExecuteBM(); } } } public class NotePrefabManager { private string notePrefabPath => Application.streamingAssetsPath + "/NotePrefabs"; private string GetNotePrefabPath(string notePrefabName) => notePrefabPath + "/" + notePrefabName + ".json"; public void SaveNotePrefab(NoteBase note, string noteName) { List clip = new List(); note.GetAllGameElementsFromThis().ForEach(e => { e.SaveBM(); clip.Add(e.matchedBM); e.submoduleList.ForEach(s => { s.SaveBM(); if (s.matchedBM != null) { clip.Add(s.matchedBM); } }); }); ES3.Save("Note", clip, GetNotePrefabPath(noteName), ProjectManager.SaveSettings); } public void LoadNotePrefab(NoteBase target, string noteName) { List clip = ES3.Load>("Note", GetNotePrefabPath(noteName), ProjectManager.SaveSettings); if (clip == null || clip.Count == 0) { LogWindow.Log("Note prefab not found", Color.red); return; } target.SaveBM(); GameElement_BM.identifier.TryAdd(target.elementGuid, target.matchedBM as GameElement_BM); (target.matchedBM as GameElement_BM).matchedElement = target; GameElement_BM first = clip[0] as GameElement_BM; List firstAttaches = GameElement_BM.GetAllAttachedBaseElements(first, clip); first.elementGuid = target.elementGuid; GameElement_BM.identifier.TryAdd(first.elementGuid, first); firstAttaches.ForEach(e => { e.attachedElementGuid = first.elementGuid; }); for (var index = 1; index < clip.Count; index++) { var element = clip[index]; if (element is GameElement_BM gameElement) { List attachedElements = GameElement_BM.GetAllAttachedBaseElements(gameElement, clip); gameElement.elementGuid = Guid.NewGuid(); GameElement_BM.identifier.TryAdd(gameElement.elementGuid, gameElement); attachedElements.ForEach(e => { e.attachedElementGuid = gameElement.elementGuid; }); } } for (var index = 1; index < clip.Count; index++) { clip[index].ExecuteBM(); } } } public class AutoSaveManager { private string autoSavePath => Application.streamingAssetsPath + "/AutoSave/" + EditorManager.instance.projectInformation.projectName; private string GetAutoSavePath(string autoSaveName) => autoSavePath + "/" + autoSaveName + ".json"; private float autoSaveInterval => EditorManager.instance.editorSettings.autoSaveInterval; private int maximumAutoSaveCount => EditorManager.instance.editorSettings.maximumAutoSaveCount; public float autoSaveTimer; public AutoSaveManager() { autoSaveTimer = 0; } public void UpdateAutoSave() { autoSaveTimer += Time.deltaTime; if (autoSaveTimer >= autoSaveInterval) { AutoSave(); autoSaveTimer = 0; } } private void AutoSave() { List saveFiles = GetSortedSaveFiles(); if (saveFiles.Count > 0) { // 删除最旧的存档(如果超过数量) if (saveFiles.Count >= maximumAutoSaveCount) { string oldestSave = saveFiles[saveFiles.Count - 1]; File.Delete(oldestSave); saveFiles.RemoveAt(saveFiles.Count - 1); } // 依次重命名存档 for (int i = saveFiles.Count - 1; i >= 0; i--) { string oldPath = saveFiles[i]; string newPath = GetAutoSavePath($"AutoSave_{i + 1}"); File.Move(oldPath, newPath); } } // 保存最新存档 string newestSavePath = GetAutoSavePath("AutoSave_0"); SaveBeatMap(newestSavePath); } private void SaveBeatMap(string autoSavePath) { EditorManager.instance.beatmapContainer.SaveBM(); ES3.Save("BeatMap", EditorManager.instance.beatmapContainer.matchedBM as BeatmapContainer_BM, autoSavePath, ProjectManager.SaveSettings); } private List GetSortedSaveFiles() { if(!ES3.DirectoryExists(autoSavePath)) { Directory.CreateDirectory(autoSavePath); } List saveFiles = new List(Directory.GetFiles(autoSavePath, "AutoSave_*.es3")); saveFiles.Sort(string.Compare); return saveFiles; } } }