using System.Collections; using System.Collections.Generic; using System.Linq; using Ichni.RhythmGame; using Ichni.RhythmGame.Beatmap; using UnityEngine; using UnityEngine.InputSystem; namespace Ichni.Editor { public class OperationManager { public List currentSelectedElements { get; private set; } public TempOutlineModule TempOutlineModule = new TempOutlineModule(); public CopyPasteDeleteModule CopyPasteDeleteModule; public FindingModule FindingModule; public OperationManager() { currentSelectedElements = new List(); CopyPasteDeleteModule = new CopyPasteDeleteModule(); FindingModule = new FindingModule(); } public void AddSelectElement(GameElement gameElement) { if (gameElement == null || gameElement.connectedTab == null) return; if (currentSelectedElements.Contains(gameElement)) return; currentSelectedElements.Add(gameElement); gameElement.connectedTab.isSelected = true; if (gameElement.connectedTab.BgImage != null) { gameElement.connectedTab.BgImage.color = new Color(0f, 0f, 0f, 0.8f); } } public void RemoveSelectElement(GameElement gameElement) { if (gameElement == null) return; currentSelectedElements.Remove(gameElement); if (gameElement.connectedTab == null) return; gameElement.connectedTab.isSelected = false; if (gameElement.connectedTab.BgImage != null) { gameElement.connectedTab.BgImage.color = new Color(0.5f, 0.5f, 0.5f, 0); } } public void ClearSelectedElements() { currentSelectedElements.RemoveAll(gameElement => gameElement == null); currentSelectedElements.ForEach(gameElement => { if (gameElement == null || gameElement.connectedTab == null) return; gameElement.connectedTab.isSelected = false; if (gameElement.connectedTab.BgImage != null) { gameElement.connectedTab.BgImage.color = new Color(0.5f, 0.5f, 0.5f, 0); } }); currentSelectedElements.Clear(); } } public class TempOutlineModule { public List outlinedElements; public Material outlineMaterial => EditorManager.instance.basePrefabs.outlineShaderMaterial; public TempOutlineModule() { outlinedElements = new List(); } public void AddOutline(GameElement gameElement) { outlinedElements.Add(gameElement); } public void RemoveOutline(GameElement gameElement) { outlinedElements.Remove(gameElement); } public void ClearOutline() { outlinedElements.Clear(); } } public class FindingModule { public GameElement FindGameElementByName(string elementName) { foreach (GameElement element in EditorManager.instance.beatmapContainer.gameElementList) { if (element.elementName == elementName) { return element; } } LogWindow.Log("Element not found: " + elementName, Color.red); return null; } } public class CopyPasteDeleteModule { public GameElement copiedElement; public List pastedElementList; public void CopyElement(GameElement gameElement) { if (gameElement == null) { LogWindow.Log("No element selected to copy.", Color.red); return; } LogWindow.Log("Copied element: " + gameElement.elementName); copiedElement = gameElement; } public void PasteElement(GameElement parentElement) { if (parentElement == null) { LogWindow.Log("No parent element selected to paste.", Color.red); return; } if (copiedElement == null) { LogWindow.Log("No element copied."); return; } LogWindow.Log("Pasted element: " + copiedElement.elementName + " to " + parentElement.elementName); pastedElementList = new List(); AffiliatedPaste(copiedElement, parentElement); // 粘贴完成后,对所有新生成的元素执行 AfterInitialize 和 Refresh, // 与 EditorManager.LoadProject 的加载后流程对齐,确保 Manager 注册等关键步骤不遗漏。 foreach (GameElement pasted in pastedElementList) { if (pasted == null) continue; pasted.AfterInitialize(); pasted.Refresh(); } } public void DeleteElement(GameElement gameElement) { if (gameElement == null) { LogWindow.Log("No element selected to delete.", Color.red); return; } LogWindow.Log("Deleted element: " + gameElement.elementName + " and all its children."); if (gameElement.parentElement != null) { gameElement.parentElement.childElementList.Remove(gameElement); //从父物体的子物体列表中移除,避免报null gameElement.parentElement.connectedTab.childTabList.Remove(gameElement.connectedTab); gameElement.parentElement.connectedTab.SetStatus(); } EditorManager.instance.operationManager.RemoveSelectElement(gameElement); gameElement.Delete(); EditorManager.instance.uiManager.inspector.ClearInspector(); } /// /// 使用递归的方式复制粘贴物体及其所有子物体 /// /// 将要被粘贴的物体 /// (将要)被粘贴物体的父物体 /// private void AffiliatedPaste(GameElement gameElement, GameElement parent) { if (gameElement == null || parent == null) return; gameElement.SaveBM(); if (gameElement.matchedBM is not GameElement_BM gameElementBM) { LogWindow.Log("Paste failed: " + gameElement.elementName + " did not create a valid BM.", Color.red); return; } GameElement pastedElement = gameElementBM.DuplicateBM(parent); if (pastedElement == null) { LogWindow.Log("Paste failed: " + gameElement.elementName + " could not be duplicated.", Color.red); return; } pastedElementList.Add(pastedElement); gameElement.submoduleList.ForEach(submodule => { if (submodule == null) return; Debug.Log(submodule.GetType() + " is pasted."); submodule.SaveBM(); if (submodule.matchedBM is not Submodule_BM submoduleBM) return; SubmoduleBase existingSubmodule = pastedElement.submoduleList .FirstOrDefault(pastedSubmodule => pastedSubmodule != null && pastedSubmodule.GetType() == submodule.GetType()); existingSubmodule?.Delete(); try { submoduleBM.DuplicateBM(pastedElement); } catch { Debug.LogWarning("Submodule paste error: " + submodule.GetType()); } }); if (gameElement.childElementList != null) { foreach (GameElement Element in gameElement.childElementList.Where(x => !pastedElementList.Contains(x))) { AffiliatedPaste(Element, pastedElement); } } } } }