using System; using System.Collections; using System.Collections.Generic; using Ichni.Editor; using Ichni.RhythmGame; using Ichni.RhythmGame.Beatmap; using Sirenix.OdinInspector; using SLSUtilities.General; using UnityEngine; namespace Ichni { /// /// 谱面数据容器。 /// 继承自 GameElement,作为编辑器中"游戏世界"的根节点, /// 持有 projectInformation / songInformation / beatmapContainer / commandScripts /// 等所有与谱面/游戏内容直接相关的数据。 /// 由 EditorManager 在场景中持有引用,并通过 EditorManager 的转发属性对外暴露, /// 以实现零调用点改动的架构迁移。 /// public class ProjectContainer : GameElement { #region [单例] Singleton private static ProjectContainer _instance; public static ProjectContainer instance => _instance != null ? _instance : _instance = FindFirstObjectByType(); #endregion #region [谱面数据] Project Data public ProjectInformation projectInformation; public SongInformation songInformation; public BeatmapContainer beatmapContainer; public CommandScripts commandScripts; #endregion #region [游戏全局元素] Global Game Elements [Title("Runtime Global Elements")] public VariablesContainer variablesContainer; public BackgroundSetter backgroundSetter; #endregion #region [编辑器首选项] Editor Preferences // 这些首选项字段放在 ProjectContainer 中,以便 SetUpInspector 将 this 作为 IBaseElement owner 传给 GenerateToggle public NoteBase.NoteJudgeType currentJudgeType; public bool useClickSelect = true; public bool useNotePrefab = true; public bool useQuickMove = false; #endregion #region [生成与初始化] Generation & Initialization private void Awake() { _instance = this; } #endregion #region [编辑器界面] Inspector public override void SetUpInspector() { IHaveInspection inspector = EditorManager.instance.uiManager.inspector; var container = inspector.GenerateContainer("Editor Manager"); var inGameSettings = container.GenerateSubcontainer(3); inspector.GenerateDropdown(this, inGameSettings, "Judge Type", typeof(NoteBase.NoteJudgeType), nameof(currentJudgeType)) .AddListenerFunction(() => { foreach (GameElement gameElement in beatmapContainer.gameElementList) { if (gameElement is NoteVisualBase noteVisual) { noteVisual.Recover(); } } }); inspector.GenerateToggle(this, inGameSettings, "Use Note Prefab", nameof(useNotePrefab)); inspector.GenerateToggle(this, inGameSettings, "Use Click Select", nameof(useClickSelect)); inspector.GenerateToggle(this, inGameSettings, "Use Quick Move", nameof(useQuickMove)); var generation = container.GenerateSubcontainer(3); inspector.GenerateButton(this, generation, "Generate Folder", () => ElementFolder.GenerateElement("Folder", Guid.NewGuid(), new List(), true, null)); inspector.GenerateButton(this, generation, "Generate Background Setter", () => BackgroundSetter.GenerateElement("Background Setter", Guid.NewGuid(), new List(), true, null, false, "basic", "Skybox", "Background")); inspector.GenerateButton(this, generation, "Generate Variables Container", () => VariablesContainer.GenerateElement("Variables Container", Guid.NewGuid(), new List(), true, null, new Dictionary())); projectInformation.SetUpInspector(); songInformation.SetUpInspector(); EditorManager.instance.cameraManager.SetUpInspector(); var oo = inspector.GenerateContainer("Grid"); var p = oo.GenerateSubcontainer(3); var po = inspector.GenerateToggle(this, p, "Enable Grid"); po.AddListenerFunction(() => { EditorManager.instance.gridController.gameObject.SetActive(po.toggle.isOn); }); var o = inspector.GenerateInputField(p, "Grid Size", (EditorManager.instance.gridController.baseGridSize * 10).ToString()); o.AddListenerFunction(() => { EditorManager.instance.gridController.baseGridSize = float.Parse(o.inputField.text) / 10; }); var sc = inspector.GenerateToggle(this, p, "Show Coordinates"); sc.toggle.isOn = EditorManager.instance.gridController.showCoordinates; sc.AddListenerFunction(() => { EditorManager.instance.gridController.showCoordinates = sc.toggle.isOn; }); } #endregion } }