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 AutoSaveManager autoSaveManager; public ProjectManager() { saveManager = new SaveManager(); loadManager = new LoadManager(); exportManager = new ExportManager(); beatmapClipManager = new BeatmapClipManager(); autoSaveManager = new AutoSaveManager(); } public void GenerateProject(string projectName) { EditorManager.instance.projectInformation = new ProjectInformation(projectName, "Soullies", "2.0", DateTime.Now.ToString(CultureInfo.CurrentCulture), DateTime.Now.ToString(CultureInfo.CurrentCulture), new List()); EditorManager.instance.songInformation = new SongInformation("TestSong", 120, 0); EditorManager.instance.beatmapContainer = new BeatmapContainer(); EditorManager.instance.commandScripts = new CommandScripts(new List()); //Create project folder if (!System.IO.Directory.Exists(EditorManager.instance.projectInformation.projectPath)) { System.IO.Directory.CreateDirectory(EditorManager.instance.projectInformation.projectPath); } } } 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 IEnumerator Load(string projectName) { LoadProjectInfo(projectName); LoadSongInfo(); LoadCommandScripts(); while (ThemeBundleManager.instance.waitingBundleAmount != 0) { yield return new WaitForEndOfFrame(); } 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 Save(string clipName) { LogWindow.Log("Start Saving Clip..."); GameElement selectedElement = EditorManager.instance.operationManager.currentSelectedElement; if (selectedElement is not ElementFolder folder) { LogWindow.Log("Please select a folder to save the beatmap clip.", Color.red); return; } SaveClip(folder, clipName); LogWindow.Log("Save Clip Complete", Color.green); } public void Load(string clipName) { LogWindow.Log("Start Loading Clip..."); if(!ES3.FileExists(Application.streamingAssetsPath + "/Clips/" + clipName + ".json")) { LogWindow.Log("Clip not found", Color.red); return; } LoadClip(clipName); LogWindow.Log("Load Clip Complete", Color.green); } public void SaveClip(ElementFolder folder, string clipName) { List clip = new List(); folder.SaveBM(); folder.matchedBM.attachedElementGuid = Guid.Empty; clip.Add(folder.matchedBM); folder.submoduleList.ForEach(s => { s.SaveBM(); clip.Add(s.matchedBM); }); folder.GetAllGameElementsFromThis(false).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); } public void LoadClip(string clipName) { List GetAllAttachedBaseElements(GameElement_BM gameElement, List clip) { Guid elementGuid = gameElement.elementGuid; List result = new List(); foreach (BaseElement_BM element in clip) { if (element.attachedElementGuid == elementGuid) { result.Add(element); } } return result; } string filePath = Application.streamingAssetsPath + "/Clips/" + clipName + ".json"; List clip = ES3.Load>("Clip", filePath, ProjectManager.SaveSettings); foreach (BaseElement_BM element in clip) { if (element is GameElement_BM gameElement) { List attachedElements = GetAllAttachedBaseElements(gameElement, clip); gameElement.elementGuid = Guid.NewGuid(); GameElement_BM.identifier.TryAdd(gameElement.elementGuid, gameElement); attachedElements.ForEach(e => { e.attachedElementGuid = gameElement.elementGuid; }); } } clip.ForEach(e => e.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; } } }