大修
This commit is contained in:
@@ -1,24 +1,33 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Dreamteck.Splines.Primitives;
|
||||
using Ichni.Editor;
|
||||
using Ichni.RhythmGame;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using Ichni.RhythmGame.ThemeBundles.Basic;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSUtilities.General;
|
||||
using TMPro;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni
|
||||
{
|
||||
public class EditorManager : GameElement
|
||||
/// <summary>
|
||||
/// 编辑器全局管理器。
|
||||
/// 继承自 Singleton<EditorManager>,只持有编辑器基础设施引用:
|
||||
/// 子管理器、音频播放器、UI、相机、设置、首选项等。
|
||||
/// 游戏/谱面数据由 ProjectContainer 持有;
|
||||
/// 此处的属性均为转发属性,保持所有外部调用点零改动。
|
||||
/// </summary>
|
||||
public class EditorManager : Singleton<EditorManager>
|
||||
{
|
||||
public static EditorManager instance;
|
||||
#region [单例别名] Singleton Alias
|
||||
/// <summary>小写别名,兼容现有调用点</summary>
|
||||
public new static EditorManager instance => Instance;
|
||||
#endregion
|
||||
|
||||
#region [加载状态] Load State
|
||||
public bool isLoaded;
|
||||
#endregion
|
||||
|
||||
#region [编辑器基础设施管理器] Editor Infrastructure Managers
|
||||
public ProjectManager projectManager;
|
||||
public AudioManager audioManager;
|
||||
public MusicPlayer musicPlayer;
|
||||
@@ -29,39 +38,96 @@ namespace Ichni
|
||||
public SimpleGridController gridController;
|
||||
public CameraManager cameraManager;
|
||||
public NoteManager noteManager;
|
||||
public Ichni.Editor.PostProcessingManager postProcessingManager;
|
||||
public TrackManager trackManager;
|
||||
public AnimationManager animationManager;
|
||||
public Canvas judgeHintCanvas;
|
||||
public Canvas inspectorCanvas;
|
||||
public Timeline timeline;
|
||||
|
||||
public ProjectInformation projectInformation;
|
||||
public SongInformation songInformation;
|
||||
public BeatmapContainer beatmapContainer;
|
||||
public CommandScripts commandScripts;
|
||||
|
||||
public PanelDrawer panelDrawer;
|
||||
public NoteBase.NoteJudgeType currentJudgeType;
|
||||
public bool useClickSelect;
|
||||
public bool useNotePrefab;
|
||||
public bool ExpandWhileClick;
|
||||
public bool useQuickMove;
|
||||
#endregion
|
||||
|
||||
#region [编辑器首选项转发属性] Editor Preferences Forwarding Properties
|
||||
// 实际字段在 ProjectContainer 中定义,此处为转发属性以保持所有调用点不变
|
||||
public NoteBase.NoteJudgeType currentJudgeType
|
||||
{
|
||||
get => ProjectContainer.instance.currentJudgeType;
|
||||
set => ProjectContainer.instance.currentJudgeType = value;
|
||||
}
|
||||
public bool useClickSelect
|
||||
{
|
||||
get => ProjectContainer.instance.useClickSelect;
|
||||
set => ProjectContainer.instance.useClickSelect = value;
|
||||
}
|
||||
public bool useNotePrefab
|
||||
{
|
||||
get => ProjectContainer.instance.useNotePrefab;
|
||||
set => ProjectContainer.instance.useNotePrefab = value;
|
||||
}
|
||||
public bool ExpandWhileClick
|
||||
{
|
||||
get => ProjectContainer.instance.ExpandWhileClick;
|
||||
set => ProjectContainer.instance.ExpandWhileClick = value;
|
||||
}
|
||||
public bool useQuickMove
|
||||
{
|
||||
get => ProjectContainer.instance.useQuickMove;
|
||||
set => ProjectContainer.instance.useQuickMove = value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region [预制体资产集合] Prefab Asset Collections
|
||||
public BasePrefabsCollection basePrefabs;
|
||||
public Dictionary<string, CustomPrefabsCollection> customPrefabs;
|
||||
|
||||
|
||||
public NoteAudioCollection noteAudioCollection;
|
||||
#endregion
|
||||
|
||||
[Title("Runtime Global Elements")]
|
||||
public VariablesContainer variablesContainer;
|
||||
public BackgroundSetter backgroundSetter;
|
||||
|
||||
private void Awake()
|
||||
#region [ProjectContainer 转发属性] ProjectContainer Forwarding Properties
|
||||
// 以下属性保持与原 EditorManager 完全相同的访问路径,
|
||||
// 内部转发至 ProjectContainer,无需修改任何调用点。
|
||||
public ProjectInformation projectInformation
|
||||
{
|
||||
instance = this;
|
||||
get => ProjectContainer.instance.projectInformation;
|
||||
set => ProjectContainer.instance.projectInformation = value;
|
||||
}
|
||||
public SongInformation songInformation
|
||||
{
|
||||
get => ProjectContainer.instance.songInformation;
|
||||
set => ProjectContainer.instance.songInformation = value;
|
||||
}
|
||||
public BeatmapContainer beatmapContainer
|
||||
{
|
||||
get => ProjectContainer.instance.beatmapContainer;
|
||||
set => ProjectContainer.instance.beatmapContainer = value;
|
||||
}
|
||||
public CommandScripts commandScripts
|
||||
{
|
||||
get => ProjectContainer.instance.commandScripts;
|
||||
set => ProjectContainer.instance.commandScripts = value;
|
||||
}
|
||||
public VariablesContainer variablesContainer
|
||||
{
|
||||
get => ProjectContainer.instance.variablesContainer;
|
||||
set => ProjectContainer.instance.variablesContainer = value;
|
||||
}
|
||||
public BackgroundSetter backgroundSetter
|
||||
{
|
||||
get => ProjectContainer.instance.backgroundSetter;
|
||||
set => ProjectContainer.instance.backgroundSetter = value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region [生命周期] Lifecycle
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake(); // Singleton<T>.Initialize(false)
|
||||
isLoaded = false;
|
||||
projectManager = new ProjectManager();
|
||||
operationManager = new OperationManager();
|
||||
|
||||
// 注册时间提供者:让编辑器的所有时间相关逻辑通过 CoreServices.TimeProvider 访问,
|
||||
// 不再直接依赖 EditorManager.instance.musicPlayer
|
||||
CoreServices.TimeProvider = musicPlayer;
|
||||
|
||||
if (!ES3.FileExists(Application.streamingAssetsPath + "/EditorSettings.es3"))
|
||||
{
|
||||
editorSettings = new EditorSettings(300, 3, 100, 100, 60);
|
||||
@@ -78,31 +144,78 @@ namespace Ichni
|
||||
private void Start()
|
||||
{
|
||||
StartCoroutine(StartFrameRate());
|
||||
Debug.Log("EditorManager Start: Initializing UI and Loading Project...");
|
||||
// ProjectContainer 自身作为根节点注册到层级视图
|
||||
ProjectContainer.instance.elementName = "EditorManager";
|
||||
ProjectContainer.instance.elementGuid = Guid.Empty;
|
||||
uiManager.hierarchy.GenerateTab(ProjectContainer.instance, null);
|
||||
ProjectContainer.instance.connectedTab.deleteButton.gameObject.SetActive(false);
|
||||
|
||||
|
||||
this.elementName = "EditorManager";
|
||||
this.elementGuid = Guid.Empty;
|
||||
uiManager.hierarchy.GenerateTab(this, null);
|
||||
this.connectedTab.deleteButton.gameObject.SetActive(false);
|
||||
if (InformationTransistor.instance.isLoadedProject)
|
||||
{
|
||||
LoadProject(InformationTransistor.instance.loadedProjectName);
|
||||
Debug.Log("Loaded");
|
||||
}
|
||||
else
|
||||
{
|
||||
projectManager.GenerateEmptyProject(InformationTransistor.instance.projectInfo_BM, InformationTransistor.instance.songInfo_BM);
|
||||
projectManager.GenerateEmptyProject(
|
||||
InformationTransistor.instance.projectInfo_BM,
|
||||
InformationTransistor.instance.songInfo_BM);
|
||||
projectManager.saveManager.Save();
|
||||
musicPlayer.audioSource.clip = songInformation.song;
|
||||
Debug.Log("Generated");
|
||||
}
|
||||
|
||||
StartCoroutine(beatmapContainer.AfterLoadSet());
|
||||
isLoaded = true;
|
||||
songInformation.songTime = musicPlayer.audioSource.time - songInformation.offset;
|
||||
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
|
||||
projectManager.autoSaveManager.UpdateAutoSave();
|
||||
|
||||
// 统一调度: Animation → Submodules → Track → Note
|
||||
float songTime = CoreServices.TimeProvider.SongTime;
|
||||
|
||||
animationManager.ManualTick(songTime);
|
||||
|
||||
// 手动执行原本属于 UniRx 的每帧调度,消灭不可控的时序错乱
|
||||
for (int i = 0; i < beatmapContainer.gameElementList.Count; i++)
|
||||
{
|
||||
var element = beatmapContainer.gameElementList[i];
|
||||
if (element == null) continue;
|
||||
|
||||
if (element is IHaveTimeDurationSubmodule timeHost && !(element is NoteBase))
|
||||
{
|
||||
timeHost.timeDurationSubmodule?.UpdateTimeDuration(songTime);
|
||||
}
|
||||
|
||||
if (element.gameObject.activeSelf)
|
||||
{
|
||||
if (element is IHaveTransformSubmodule transformHost)
|
||||
{
|
||||
transformHost.UpdateTransform();
|
||||
}
|
||||
if (element is IHaveColorSubmodule colorHost)
|
||||
{
|
||||
colorHost.UpdateColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trackManager.ManualTick(songTime);
|
||||
noteManager.ManualTick(songTime);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region [FPS 监控] FPS Monitor
|
||||
public float CurrentFrameRate;
|
||||
public TMP_Text FPStext;
|
||||
public TMP_Text UIText;
|
||||
|
||||
private IEnumerator StartFrameRate()
|
||||
{
|
||||
int frameCount = 0;
|
||||
@@ -118,13 +231,9 @@ namespace Ichni
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (isLoaded) projectManager.autoSaveManager.UpdateAutoSave();
|
||||
|
||||
}
|
||||
|
||||
#region [项目加载] Project Loading
|
||||
public void LoadProject(string projectName)
|
||||
{
|
||||
if (!InformationTransistor.instance.isRecovery)
|
||||
@@ -144,107 +253,34 @@ namespace Ichni
|
||||
gameElement.Refresh();
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = uiManager.inspector;
|
||||
|
||||
var container = inspector.GenerateContainer("Editor Manager");
|
||||
|
||||
var inGameSettings = container.GenerateSubcontainer(3);
|
||||
var judgeTypeDropdown = 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();
|
||||
}
|
||||
}
|
||||
});
|
||||
var useNotePrefabToggle =
|
||||
inspector.GenerateToggle(this, inGameSettings, "Use Note Prefab", nameof(useNotePrefab));
|
||||
var useClickSelectToggle =
|
||||
inspector.GenerateToggle(this, inGameSettings, "Use Click Select", nameof(useClickSelect));
|
||||
var ExpandWhileClickToggle =
|
||||
inspector.GenerateToggle(this, inGameSettings, "Expand Tab While Click", nameof(ExpandWhileClick));
|
||||
|
||||
var useQuickMoveToggle =
|
||||
inspector.GenerateToggle(this, inGameSettings, "Use Quick Move", nameof(useQuickMove));
|
||||
|
||||
var generation = container.GenerateSubcontainer(3);
|
||||
var generateFolderButton =
|
||||
inspector.GenerateButton(this, generation, "Generate Folder",
|
||||
() => ElementFolder.GenerateElement("Folder", Guid.NewGuid(),
|
||||
new List<string>(), true, null));
|
||||
var generateBackgroundSetterButton =
|
||||
inspector.GenerateButton(this, generation, "Generate Background Setter",
|
||||
() => BackgroundSetter.GenerateElement("Background Setter", Guid.NewGuid(),
|
||||
new List<string>(), true, null, false,
|
||||
"basic", "Skybox", "Background"));
|
||||
var generateVariablesContainerButton =
|
||||
inspector.GenerateButton(this, generation, "Generate Variables Container",
|
||||
() => VariablesContainer.GenerateElement("Variables Container", Guid.NewGuid(),
|
||||
new List<string>(), true, null, new Dictionary<string, int>()));
|
||||
|
||||
projectInformation.SetUpInspector();
|
||||
songInformation.SetUpInspector();
|
||||
cameraManager.SetUpInspector();
|
||||
var oo = inspector.GenerateContainer("Grid");
|
||||
var p = oo.GenerateSubcontainer(3);
|
||||
var po = inspector.GenerateToggle(this, p, "Enable Grid");
|
||||
po.AddListenerFunction(() =>
|
||||
{
|
||||
gridController.gameObject.SetActive(po.toggle.isOn);
|
||||
});
|
||||
var o = inspector.GenerateInputField(p, "Grid Size", (gridController.baseGridSize * 10).ToString());
|
||||
o.AddListenerFunction(() =>
|
||||
{
|
||||
gridController.baseGridSize = float.Parse(o.inputField.text) / 10;
|
||||
});
|
||||
var c = inspector.GenerateToggle(this, p, "Show Coordinates", nameof(gridController) + "." + nameof(gridController.showCoordinates));
|
||||
}
|
||||
|
||||
|
||||
#region [退出处理] Application Quit
|
||||
private bool isQuit = false;
|
||||
|
||||
[Obsolete]
|
||||
public void OnApplicationQuit()
|
||||
{
|
||||
if (isQuit) return;
|
||||
|
||||
Application.CancelQuit();//退出拦截
|
||||
Application.CancelQuit(); // 退出拦截
|
||||
GeneralSecondaryWindow QuitWindow =
|
||||
Instantiate(EditorManager.instance.basePrefabs.generalSecondaryWindow,
|
||||
EditorManager.instance.uiManager.mainPage.mainCanvas.GetComponent<RectTransform>()).GetComponent<GeneralSecondaryWindow>();
|
||||
Instantiate(instance.basePrefabs.generalSecondaryWindow,
|
||||
instance.uiManager.mainPage.mainCanvas.GetComponent<RectTransform>())
|
||||
.GetComponent<GeneralSecondaryWindow>();
|
||||
|
||||
QuitWindow.Initialize("Do You Want To Save?");
|
||||
|
||||
|
||||
var container = QuitWindow.GenerateContainer("Save confirm");
|
||||
var beatmapToolsSettings = container.GenerateSubcontainer(3);
|
||||
var yesButton = QuitWindow.GenerateButton(beatmapToolsSettings, "Yes", () =>
|
||||
{
|
||||
SaveAndQuit();
|
||||
|
||||
});
|
||||
var noButton = QuitWindow.GenerateButton(beatmapToolsSettings, "No", () =>
|
||||
QuitWindow.GenerateButton(beatmapToolsSettings, "Yes", () => SaveAndQuit());
|
||||
QuitWindow.GenerateButton(beatmapToolsSettings, "No", () =>
|
||||
{
|
||||
isQuit = true;
|
||||
Application.Quit();
|
||||
});
|
||||
|
||||
// if (isQuit)
|
||||
// {
|
||||
// Application.CancelQuit();//退出拦截
|
||||
// MessageCtrl.Instance.OpenConfirmView("关闭界面将终止,确认关闭?", "", () =>
|
||||
// {
|
||||
// isQuit = false;
|
||||
// Application.Quit();
|
||||
// });
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
async void SaveAndQuit()
|
||||
{
|
||||
isQuit = true;
|
||||
@@ -252,5 +288,6 @@ namespace Ichni
|
||||
await projectManager.saveManager.SaveAllCoroutine();
|
||||
Application.Quit();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user