Files
ichni_Creator_Studio/Assets/Scripts/Manager/OperationManager.cs
2026-07-29 20:14:03 +08:00

337 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Ichni.Editor.Commands;
using Ichni.RhythmGame;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
using UnityEngine.InputSystem;
namespace Ichni.Editor
{
public class OperationManager
{
public List<GameElement> currentSelectedElements { get; private set; }
public TempOutlineModule TempOutlineModule = new TempOutlineModule();
public CopyPasteDeleteModule CopyPasteDeleteModule;
public FindingModule FindingModule;
public OperationManager()
{
currentSelectedElements = new List<GameElement>();
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 AddSelectRangeToElement(GameElement targetElement)
{
if (targetElement == null) return;
GameElement parentElement = targetElement.parentElement;
List<GameElement> siblingElements = parentElement?.childElementList;
if (siblingElements == null || siblingElements.Count == 0)
{
AddSelectElement(targetElement);
return;
}
int targetIndex = siblingElements.IndexOf(targetElement);
if (targetIndex < 0)
{
AddSelectElement(targetElement);
return;
}
GameElement rangeStartElement = currentSelectedElements
.Where(element => element != null && element.parentElement == parentElement)
.Select(element => new
{
Element = element,
Index = siblingElements.IndexOf(element)
})
.Where(entry => entry.Index >= 0)
.OrderByDescending(entry => entry.Index)
.Select(entry => entry.Element)
.FirstOrDefault();
if (rangeStartElement == null)
{
if (currentSelectedElements.Count > 0)
{
LogWindow.Log("Shift range select requires sibling elements.", Color.red);
}
AddSelectElement(targetElement);
return;
}
int startIndex = siblingElements.IndexOf(rangeStartElement);
int minIndex = Mathf.Min(startIndex, targetIndex);
int maxIndex = Mathf.Max(startIndex, targetIndex);
for (int i = minIndex; i <= maxIndex; i++)
{
AddSelectElement(siblingElements[i]);
}
}
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<GameElement> outlinedElements;
public Material outlineMaterial => EditorManager.instance.basePrefabs.outlineShaderMaterial;
public TempOutlineModule()
{
outlinedElements = new List<GameElement>();
}
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<GameElement> pastedElementList;
private ElementClipboardSnapshot clipboardSnapshot;
public void CopyElement(GameElement gameElement)
{
CopyElements(new[] { gameElement });
}
public void CopyElements(IEnumerable<GameElement> gameElements)
{
if (!ElementClipboardSnapshot.TryCaptureSiblingRoots(
gameElements,
out ElementClipboardSnapshot snapshot,
out List<GameElement> orderedRoots,
out string errorMessage))
{
LogWindow.Log(errorMessage, Color.red);
return;
}
clipboardSnapshot = snapshot;
copiedElement = orderedRoots.FirstOrDefault();
string elementText = orderedRoots.Count == 1
? orderedRoots[0].elementName
: orderedRoots.Count + " sibling elements";
LogWindow.Log("Copied element: " + elementText);
}
public void CutElement(GameElement gameElement)
{
CutElements(new[] { gameElement });
}
public void CutElements(IEnumerable<GameElement> gameElements)
{
if (!ElementClipboardSnapshot.TryCaptureSiblingRoots(
gameElements,
out ElementClipboardSnapshot snapshot,
out List<GameElement> orderedRoots,
out string errorMessage))
{
LogWindow.Log(errorMessage, Color.red);
return;
}
clipboardSnapshot = snapshot;
copiedElement = orderedRoots.FirstOrDefault();
ExecuteDeleteElements(orderedRoots);
LogWindow.Log("Cut element: " + (orderedRoots.Count == 1 ? orderedRoots[0].elementName : orderedRoots.Count + " sibling elements"));
}
public void PasteElement(GameElement parentElement)
{
if (parentElement == null)
{
LogWindow.Log("No parent element selected to paste.", Color.red);
return;
}
if (clipboardSnapshot == null || clipboardSnapshot.RootCount == 0)
{
LogWindow.Log("No element copied.");
return;
}
CommandManager.ExecuteCommand(new PasteElementCommand(this, clipboardSnapshot, parentElement));
}
public GameElement PasteElementRaw(GameElement sourceElement, GameElement parentElement)
{
ElementClipboardSnapshot snapshot = sourceElement == copiedElement && clipboardSnapshot != null
? clipboardSnapshot
: ElementClipboardSnapshot.CaptureSingle(sourceElement);
return PasteElementsRaw(snapshot, parentElement).FirstOrDefault();
}
public List<GameElement> PasteElementsRaw(ElementClipboardSnapshot snapshot, GameElement parentElement)
{
pastedElementList = new List<GameElement>();
if (snapshot == null || parentElement == null) return new List<GameElement>();
ElementPasteResult pasteResult = snapshot.PasteTo(parentElement);
pastedElementList = pasteResult.AllElements;
string pastedText = pasteResult.RootElements.Count == 1
? pasteResult.RootElements[0].elementName
: pasteResult.RootElements.Count + " elements";
LogWindow.Log("Pasted element: " + pastedText + " to " + parentElement.elementName);
return pasteResult.RootElements;
}
public void DeleteElement(GameElement gameElement)
{
DeleteElements(new[] { gameElement });
}
public void DeleteElements(IEnumerable<GameElement> gameElements)
{
List<GameElement> roots = ElementClipboardSnapshot.GetTopLevelElements(gameElements);
if (roots.Count == 0)
{
LogWindow.Log("No element selected to delete.", Color.red);
return;
}
ExecuteDeleteElements(roots);
}
private void ExecuteDeleteElements(IEnumerable<GameElement> gameElements)
{
List<GameElement> roots = ElementClipboardSnapshot.GetTopLevelElements(gameElements);
if (roots.Count == 0) return;
if (roots.Count == 1)
{
CommandManager.ExecuteCommand(new DeleteElementCommand(roots[0]));
return;
}
CommandGroup commandGroup = new CommandGroup();
foreach (GameElement root in roots)
{
commandGroup.Add(new DeleteElementCommand(root));
}
if (commandGroup.Count > 0)
{
CommandManager.ExecuteCommand(commandGroup);
}
}
public void DeleteElementRaw(GameElement gameElement, bool writeLog = true)
{
if (gameElement == null) return;
var deletedElements = gameElement.GetAllGameElementsFromThis();
var deletedGuids = deletedElements.Select(element => element.elementGuid).ToList();
var deletedTabs = deletedElements
.Select(element => element.connectedTab)
.Where(tab => tab != null)
.ToList();
if (writeLog)
LogWindow.Log("Deleted element: " + gameElement.elementName + " and all its children.");
if (gameElement.parentElement != null)
{
gameElement.parentElement.childElementList.Remove(gameElement); //从父物体的子物体列表中移除避免报null
if (gameElement.parentElement.connectedTab != null)
{
gameElement.parentElement.connectedTab.childTabList.Remove(gameElement.connectedTab);
gameElement.parentElement.connectedTab.SetStatus();
}
}
deletedElements.ForEach(element => EditorManager.instance.operationManager.RemoveSelectElement(element));
gameElement.Delete();
deletedGuids.ForEach(guid => GameElement_BM.identifier.Remove(guid));
deletedTabs.ForEach(tab => EditorManager.instance.uiManager.hierarchy.tabList.Remove(tab));
EditorManager.instance.uiManager.inspector.ClearInspector();
}
}
public interface IPastedReferenceResolver
{
void ResolvePastedReferences(IReadOnlyDictionary<Guid, GameElement> pastedElementBySourceGuid);
}
}