@@ -1,5 +1,6 @@
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.RhythmGame;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.Editor.Commands
|
||||
@@ -14,6 +15,8 @@ namespace Ichni.Editor.Commands
|
||||
/// </summary>
|
||||
public static void ExecuteCommand(ICommand command)
|
||||
{
|
||||
if (command == null) return;
|
||||
|
||||
if (undoStack.Count > 0)
|
||||
{
|
||||
var topCommand = undoStack.Peek();
|
||||
@@ -28,7 +31,14 @@ namespace Ichni.Editor.Commands
|
||||
// 新操作彻底切断原本可能存在的重做未来
|
||||
command.Execute();
|
||||
undoStack.Push(command);
|
||||
redoStack.Clear();
|
||||
redoStack.Clear();
|
||||
}
|
||||
|
||||
public static GameElement ExecuteCreate(Func<GameElement> createAction)
|
||||
{
|
||||
var command = new CreateElementCommand(createAction);
|
||||
ExecuteCommand(command);
|
||||
return command.CreatedElement;
|
||||
}
|
||||
|
||||
public static void Undo()
|
||||
|
||||
245
Assets/Scripts/CommandSystem/GameElementStructuralCommands.cs
Normal file
245
Assets/Scripts/CommandSystem/GameElementStructuralCommands.cs
Normal file
@@ -0,0 +1,245 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Ichni.RhythmGame;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.Editor.Commands
|
||||
{
|
||||
internal sealed class ElementTreeSnapshot
|
||||
{
|
||||
private readonly List<BaseElement_BM> elements = new List<BaseElement_BM>();
|
||||
private readonly Guid rootGuid;
|
||||
private readonly Guid parentGuid;
|
||||
private readonly int parentChildIndex;
|
||||
|
||||
private ElementTreeSnapshot(GameElement root)
|
||||
{
|
||||
rootGuid = root.elementGuid;
|
||||
parentGuid = root.parentElement?.elementGuid ?? Guid.Empty;
|
||||
parentChildIndex = root.parentElement != null
|
||||
? root.parentElement.childElementList.IndexOf(root)
|
||||
: -1;
|
||||
|
||||
RegisterExistingAncestorChain(root.parentElement);
|
||||
|
||||
foreach (GameElement element in root.GetAllGameElementsFromThis())
|
||||
{
|
||||
if (element == null) continue;
|
||||
element.SaveBM();
|
||||
if (element.matchedBM != null)
|
||||
elements.Add(element.matchedBM);
|
||||
|
||||
element.submoduleList.RemoveAll(submodule => submodule == null);
|
||||
foreach (SubmoduleBase submodule in element.submoduleList)
|
||||
{
|
||||
submodule.SaveBM();
|
||||
if (submodule.matchedBM != null)
|
||||
elements.Add(submodule.matchedBM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ElementTreeSnapshot Capture(GameElement root)
|
||||
{
|
||||
return root == null ? null : new ElementTreeSnapshot(root);
|
||||
}
|
||||
|
||||
public GameElement Restore()
|
||||
{
|
||||
if (elements.Count == 0) return null;
|
||||
|
||||
GameElement parent = parentGuid == Guid.Empty ? null : FindExistingElement(parentGuid);
|
||||
RegisterExistingAncestorChain(parent);
|
||||
RepairRootAttachment();
|
||||
|
||||
foreach (GameElement_BM gameElementBM in elements.OfType<GameElement_BM>())
|
||||
{
|
||||
GameElement_BM.identifier[gameElementBM.elementGuid] = gameElementBM;
|
||||
}
|
||||
|
||||
foreach (BaseElement_BM elementBM in elements)
|
||||
{
|
||||
elementBM.ExecuteBM();
|
||||
}
|
||||
|
||||
EditorManager.instance.beatmapContainer.ExecuteLowPriorityActions();
|
||||
|
||||
GameElement root = GameElement_BM.GetElement(rootGuid);
|
||||
if (root == null) return null;
|
||||
|
||||
RestoreParentOrder(root, parent);
|
||||
|
||||
foreach (GameElement element in root.GetAllGameElementsFromThis())
|
||||
{
|
||||
if (element == null) continue;
|
||||
element.AfterInitialize();
|
||||
element.Refresh();
|
||||
}
|
||||
|
||||
EditorManager.instance.uiManager.hierarchy.FindTab(root);
|
||||
return root;
|
||||
}
|
||||
|
||||
private GameElement FindExistingElement(Guid elementGuid)
|
||||
{
|
||||
GameElement element = GameElement_BM.GetElement(elementGuid);
|
||||
if (element != null) return element;
|
||||
|
||||
return EditorManager.instance.beatmapContainer.gameElementList
|
||||
.FirstOrDefault(gameElement => gameElement != null && gameElement.elementGuid == elementGuid);
|
||||
}
|
||||
|
||||
private void RepairRootAttachment()
|
||||
{
|
||||
if (parentGuid == Guid.Empty) return;
|
||||
|
||||
GameElement_BM rootBM = elements
|
||||
.OfType<GameElement_BM>()
|
||||
.FirstOrDefault(gameElementBM => gameElementBM.elementGuid == rootGuid);
|
||||
|
||||
if (rootBM != null)
|
||||
{
|
||||
rootBM.attachedElementGuid = parentGuid;
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterExistingAncestorChain(GameElement parent)
|
||||
{
|
||||
if (parent == null) return;
|
||||
|
||||
List<GameElement> ancestors = new List<GameElement>();
|
||||
for (GameElement current = parent; current != null; current = current.parentElement)
|
||||
{
|
||||
ancestors.Add(current);
|
||||
}
|
||||
|
||||
ancestors.Reverse();
|
||||
foreach (GameElement ancestor in ancestors)
|
||||
{
|
||||
ancestor.SaveBM();
|
||||
if (ancestor.matchedBM is not GameElement_BM ancestorBM) continue;
|
||||
|
||||
GameElement_BM.identifier[ancestor.elementGuid] = ancestorBM;
|
||||
ancestorBM.matchedElement = ancestor;
|
||||
}
|
||||
}
|
||||
|
||||
private void RestoreParentOrder(GameElement root, GameElement parent)
|
||||
{
|
||||
if (parent == null || parentChildIndex < 0) return;
|
||||
|
||||
parent.childElementList.Remove(root);
|
||||
int insertIndex = Mathf.Clamp(parentChildIndex, 0, parent.childElementList.Count);
|
||||
parent.childElementList.Insert(insertIndex, root);
|
||||
root.transform.SetSiblingIndex(insertIndex);
|
||||
parent.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DeleteElementCommand : ICommand
|
||||
{
|
||||
private readonly ElementTreeSnapshot snapshot;
|
||||
private GameElement target;
|
||||
|
||||
public DeleteElementCommand(GameElement target)
|
||||
{
|
||||
this.target = target;
|
||||
snapshot = ElementTreeSnapshot.Capture(target);
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
DeleteCurrentTarget();
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
target = snapshot?.Restore();
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
DeleteCurrentTarget();
|
||||
}
|
||||
|
||||
public bool TryMerge(ICommand other) => false;
|
||||
|
||||
private void DeleteCurrentTarget()
|
||||
{
|
||||
if (target == null) return;
|
||||
EditorManager.instance.operationManager.CopyPasteDeleteModule.DeleteElementRaw(target);
|
||||
target = null;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PasteElementCommand : ICommand
|
||||
{
|
||||
private readonly CopyPasteDeleteModule module;
|
||||
private readonly GameElement source;
|
||||
private readonly GameElement parent;
|
||||
private ElementTreeSnapshot snapshot;
|
||||
private GameElement pastedRoot;
|
||||
|
||||
public PasteElementCommand(CopyPasteDeleteModule module, GameElement source, GameElement parent)
|
||||
{
|
||||
this.module = module;
|
||||
this.source = source;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
pastedRoot = module.PasteElementRaw(source, parent);
|
||||
snapshot ??= ElementTreeSnapshot.Capture(pastedRoot);
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
if (pastedRoot == null) return;
|
||||
module.DeleteElementRaw(pastedRoot, false);
|
||||
pastedRoot = null;
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
pastedRoot = snapshot?.Restore();
|
||||
}
|
||||
|
||||
public bool TryMerge(ICommand other) => false;
|
||||
}
|
||||
|
||||
public sealed class CreateElementCommand : ICommand
|
||||
{
|
||||
private readonly Func<GameElement> createAction;
|
||||
private ElementTreeSnapshot snapshot;
|
||||
|
||||
public GameElement CreatedElement { get; private set; }
|
||||
|
||||
public CreateElementCommand(Func<GameElement> createAction)
|
||||
{
|
||||
this.createAction = createAction;
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
CreatedElement = createAction?.Invoke();
|
||||
snapshot ??= ElementTreeSnapshot.Capture(CreatedElement);
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
if (CreatedElement == null) return;
|
||||
EditorManager.instance.operationManager.CopyPasteDeleteModule.DeleteElementRaw(CreatedElement, false);
|
||||
CreatedElement = null;
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
CreatedElement = snapshot?.Restore();
|
||||
}
|
||||
|
||||
public bool TryMerge(ICommand other) => false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96273157236b1a54fbf492d88d4c540f
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
@@ -784,29 +785,29 @@ namespace Ichni.Editor
|
||||
|
||||
builder
|
||||
.Button("Displacement", () =>
|
||||
Displacement.GenerateElement("New Displacement", Guid.NewGuid(),
|
||||
CommandManager.ExecuteCreate(() => Displacement.GenerateElement("New Displacement", Guid.NewGuid(),
|
||||
new List<string>(), true, gameElement,
|
||||
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true)))
|
||||
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true))))
|
||||
.Button("Swirl", () =>
|
||||
Swirl.GenerateElement("New Swirl", Guid.NewGuid(),
|
||||
CommandManager.ExecuteCreate(() => Swirl.GenerateElement("New Swirl", Guid.NewGuid(),
|
||||
new List<string>(), true, gameElement,
|
||||
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true)))
|
||||
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true))))
|
||||
.Button("Scale", () =>
|
||||
Scale.GenerateElement("New Scale", Guid.NewGuid(),
|
||||
CommandManager.ExecuteCreate(() => Scale.GenerateElement("New Scale", Guid.NewGuid(),
|
||||
new List<string>(), true, gameElement,
|
||||
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true)))
|
||||
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true))))
|
||||
.Button("Look At", () =>
|
||||
LookAt.GenerateElement("New Look At", Guid.NewGuid(),
|
||||
new List<string>(), true, gameElement, null, new FlexibleBool()))
|
||||
CommandManager.ExecuteCreate(() => LookAt.GenerateElement("New Look At", Guid.NewGuid(),
|
||||
new List<string>(), true, gameElement, null, new FlexibleBool())))
|
||||
.Button("Displacement Tracker", () =>
|
||||
DisplacementTracker.GenerateElement("New Displacement Tracker", Guid.NewGuid(),
|
||||
new List<string>(), true, gameElement, null, 0f))
|
||||
CommandManager.ExecuteCreate(() => DisplacementTracker.GenerateElement("New Displacement Tracker", Guid.NewGuid(),
|
||||
new List<string>(), true, gameElement, null, 0f)))
|
||||
.Button("Swirl Tracker", () =>
|
||||
SwirlTracker.GenerateElement("New Swirl Tracker", Guid.NewGuid(),
|
||||
new List<string>(), true, gameElement, null, 0f))
|
||||
CommandManager.ExecuteCreate(() => SwirlTracker.GenerateElement("New Swirl Tracker", Guid.NewGuid(),
|
||||
new List<string>(), true, gameElement, null, 0f)))
|
||||
.Button("Scale Tracker", () =>
|
||||
ScaleTracker.GenerateElement("New Scale Tracker", Guid.NewGuid(),
|
||||
new List<string>(), true, gameElement, null, 0f));
|
||||
CommandManager.ExecuteCreate(() => ScaleTracker.GenerateElement("New Scale Tracker", Guid.NewGuid(),
|
||||
new List<string>(), true, gameElement, null, 0f)));
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using DG.Tweening;
|
||||
using Lean.Pool;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
@@ -24,7 +25,8 @@ namespace Ichni.Editor
|
||||
tabList = new List<HierarchyTab>();
|
||||
addFolderButton.onClick.AddListener(() =>
|
||||
{
|
||||
ElementFolder.GenerateElement("New Folder", Guid.NewGuid(), new List<string>(), true, null);
|
||||
CommandManager.ExecuteCreate(() =>
|
||||
ElementFolder.GenerateElement("New Folder", Guid.NewGuid(), new List<string>(), true, null));
|
||||
});
|
||||
expandButtom.onClick.AddListener(Expand);
|
||||
rectTransform = this.GetComponent<RectTransform>();
|
||||
@@ -201,4 +203,4 @@ namespace Ichni.Editor
|
||||
upLoadElement = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,13 +176,7 @@ namespace Ichni.Editor
|
||||
|
||||
private void GenerateSaveClipWindow()
|
||||
{
|
||||
GameElement currentElement = EditorManager.instance.operationManager.currentSelectedElements[0];
|
||||
|
||||
if (currentElement == null)
|
||||
{
|
||||
LogWindow.Log("No Game Element selected.", Color.red);
|
||||
return;
|
||||
}
|
||||
if (!TryGetSingleSelectedElementForClip(out GameElement currentElement)) return;
|
||||
|
||||
if (clipManagementWindow != null)
|
||||
{
|
||||
@@ -208,15 +202,7 @@ namespace Ichni.Editor
|
||||
|
||||
private void GenerateLoadClipWindow()
|
||||
{
|
||||
GameElement currentElement = EditorManager.instance.operationManager.currentSelectedElements[0];
|
||||
|
||||
if (currentElement == null)
|
||||
{
|
||||
LogWindow.Log("No Game Element selected.", Color.red);
|
||||
return;
|
||||
}
|
||||
|
||||
GameElement loadTarget = currentElement == EditorManager.instance ? null : currentElement.parentElement;
|
||||
if (!TryGetSingleSelectedElementForClip(out GameElement currentElement)) return;
|
||||
|
||||
if (clipManagementWindow != null)
|
||||
{
|
||||
@@ -240,6 +226,26 @@ namespace Ichni.Editor
|
||||
});
|
||||
}
|
||||
|
||||
private bool TryGetSingleSelectedElementForClip(out GameElement currentElement)
|
||||
{
|
||||
currentElement = null;
|
||||
var selectedElements = EditorManager.instance.operationManager.currentSelectedElements;
|
||||
if (selectedElements == null || selectedElements.Count != 1)
|
||||
{
|
||||
LogWindow.Log("Please select only one Game Element for clip operation.", Color.red);
|
||||
return false;
|
||||
}
|
||||
|
||||
currentElement = selectedElements[0];
|
||||
if (currentElement == null)
|
||||
{
|
||||
LogWindow.Log("No Game Element selected.", Color.red);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void GenerateMergeWindow()
|
||||
{
|
||||
GeneralSecondaryWindow mergeWindow = Instantiate(EditorManager.instance.basePrefabs.generalSecondaryWindow,
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -37,8 +38,8 @@ namespace Ichni.RhythmGame
|
||||
.InputField(nameof(TimeOffset), "Offset")
|
||||
.Button("Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(),
|
||||
new List<string>(), true, this, InterferomType.Additive, Vector3.zero);
|
||||
CommandManager.ExecuteCreate(() => Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(),
|
||||
new List<string>(), true, this, InterferomType.Additive, Vector3.zero));
|
||||
})
|
||||
.Build();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -37,8 +38,8 @@ namespace Ichni.RhythmGame
|
||||
.InputField(nameof(TimeOffset), "Offset")
|
||||
.Button("Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(),
|
||||
new List<string>(), true, this, InterferomType.Additive, Vector3.zero);
|
||||
CommandManager.ExecuteCreate(() => Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(),
|
||||
new List<string>(), true, this, InterferomType.Additive, Vector3.zero));
|
||||
})
|
||||
.Build();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -37,8 +38,8 @@ namespace Ichni.RhythmGame
|
||||
.InputField(nameof(TimeOffset), "Offset")
|
||||
.Button("Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(),
|
||||
new List<string>(), true, this, InterferomType.Additive, Vector3.zero);
|
||||
CommandManager.ExecuteCreate(() => Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(),
|
||||
new List<string>(), true, this, InterferomType.Additive, Vector3.zero));
|
||||
})
|
||||
.Build();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -21,8 +22,8 @@ namespace Ichni.RhythmGame
|
||||
new FlexibleFloat[] { positionX, positionY, positionZ }, new string[] { "PosX", "PosY", "PosZ" }))
|
||||
.ParameterText(nameof(PreviewValue), "value:", autoUpdate: true)
|
||||
.Span(3)
|
||||
.Button("Interferometer", () => Vector3Interferometer.GenerateElement("New Vector3 Interferometer",
|
||||
Guid.NewGuid(), new List<string>(), true, this, InterferomType.Additive, Vector3.zero))
|
||||
.Button("Interferometer", () => CommandManager.ExecuteCreate(() => Vector3Interferometer.GenerateElement("New Vector3 Interferometer",
|
||||
Guid.NewGuid(), new List<string>(), true, this, InterferomType.Additive, Vector3.zero)))
|
||||
.Span(3)
|
||||
.Build();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -22,8 +23,8 @@ namespace Ichni.RhythmGame
|
||||
new string[] { "ScaleX", "ScaleY", "ScaleZ" }))
|
||||
.ParameterText(nameof(PreviewValue), "value:", autoUpdate: true)
|
||||
.Span(3)
|
||||
.Button("Interferometer", () => Vector3Interferometer.GenerateElement("New Vector3 Interferometer",
|
||||
Guid.NewGuid(), new List<string>(), true, this, InterferomType.Additive, Vector3.zero))
|
||||
.Button("Interferometer", () => CommandManager.ExecuteCreate(() => Vector3Interferometer.GenerateElement("New Vector3 Interferometer",
|
||||
Guid.NewGuid(), new List<string>(), true, this, InterferomType.Additive, Vector3.zero)))
|
||||
.Span(3)
|
||||
.Build();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -22,8 +23,8 @@ namespace Ichni.RhythmGame
|
||||
new string[] { "EulerX", "EulerY", "EulerZ" }))
|
||||
.ParameterText(nameof(PreviewValue), "value:", autoUpdate: true)
|
||||
.Span(3)
|
||||
.Button("Interferometer", () => Vector3Interferometer.GenerateElement("New Vector3 Interferometer",
|
||||
Guid.NewGuid(), new List<string>(), true, this, InterferomType.Additive, Vector3.zero))
|
||||
.Button("Interferometer", () => CommandManager.ExecuteCreate(() => Vector3Interferometer.GenerateElement("New Vector3 Interferometer",
|
||||
Guid.NewGuid(), new List<string>(), true, this, InterferomType.Additive, Vector3.zero)))
|
||||
.Span(3)
|
||||
.Build();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -23,41 +24,41 @@ namespace Ichni.RhythmGame
|
||||
var builder = InspectorBuilder.For(this)
|
||||
.Section("Generate")
|
||||
.Button("Environment Object", () =>
|
||||
TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(),
|
||||
new List<string>(), true, this))
|
||||
CommandManager.ExecuteCreate(() => TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(),
|
||||
new List<string>(), true, this)))
|
||||
.Toggle(nameof(isStatic), "Is Static")
|
||||
.OnChanged(() => gameObject.isStatic = isStatic)
|
||||
.Preset(InspectorBuilder.TransformPreset)
|
||||
.Section("Generate Animations")
|
||||
.Button("Base Color Change", () =>
|
||||
BaseColorChange.GenerateElement("New Base Color Change", Guid.NewGuid(), new List<string>(), true,
|
||||
CommandManager.ExecuteCreate(() => BaseColorChange.GenerateElement("New Base Color Change", Guid.NewGuid(), new List<string>(), true,
|
||||
this,
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.r, colorSubmodule.originalBaseColor.r, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.g, colorSubmodule.originalBaseColor.g, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.b, colorSubmodule.originalBaseColor.b, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.a, colorSubmodule.originalBaseColor.a, animationCurveType: AnimationCurveType.Linear) })
|
||||
));
|
||||
)));
|
||||
|
||||
if (haveEmissionColor)
|
||||
{
|
||||
builder.Button("Emission Color Change", () =>
|
||||
EmissionColorChange.GenerateElement("New Emission Color Change", Guid.NewGuid(),
|
||||
CommandManager.ExecuteCreate(() => EmissionColorChange.GenerateElement("New Emission Color Change", Guid.NewGuid(),
|
||||
new List<string>(), true, this,
|
||||
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat()));
|
||||
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat())));
|
||||
}
|
||||
|
||||
builder
|
||||
.Button("Property Animation Color", () =>
|
||||
PropertyAnimationColor.GenerateElement("New Property Animation Color", Guid.NewGuid(),
|
||||
CommandManager.ExecuteCreate(() => PropertyAnimationColor.GenerateElement("New Property Animation Color", Guid.NewGuid(),
|
||||
new List<string>(), true, this, GetType().FullName, "",
|
||||
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat()))
|
||||
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat())))
|
||||
.Button("Property Animation Float", () =>
|
||||
PropertyAnimationFloat.GenerateElement("New Property Animation Float", Guid.NewGuid(),
|
||||
new List<string>(), true, this, GetType().FullName, "", new FlexibleFloat()))
|
||||
CommandManager.ExecuteCreate(() => PropertyAnimationFloat.GenerateElement("New Property Animation Float", Guid.NewGuid(),
|
||||
new List<string>(), true, this, GetType().FullName, "", new FlexibleFloat())))
|
||||
.Button("Property Animation Vector3", () =>
|
||||
PropertyAnimationVector3.GenerateElement("New Property Animation Vector3", Guid.NewGuid(),
|
||||
CommandManager.ExecuteCreate(() => PropertyAnimationVector3.GenerateElement("New Property Animation Vector3", Guid.NewGuid(),
|
||||
new List<string>(), true, this, GetType().FullName, "",
|
||||
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat()))
|
||||
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat())))
|
||||
.Build();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse;
|
||||
using Sirenix.OdinInspector;
|
||||
@@ -26,29 +27,29 @@ namespace Ichni.RhythmGame
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Generate", sectionOrder: 10)
|
||||
.Button("Folder", () => ElementFolder.GenerateElement("New Folder", Guid.NewGuid(), new List<string>(), true, this))
|
||||
.Button("Track", () => Track.GenerateElement("New Track", Guid.NewGuid(), new List<string>(), true, this))
|
||||
.Button("Camera", () => GameCamera.GenerateElement("New Camera", Guid.NewGuid(), new List<string>(), true, this, GameCamera.CameraViewType.Perspective, 60, 10))
|
||||
.Button("Cross Track Point", () => CrossTrackPoint.GenerateElement("New Cross Track Point", Guid.NewGuid(), new List<string>(), true, this, new FlexibleInt(), new FlexibleFloat()))
|
||||
.Button("Folder", () => CommandManager.ExecuteCreate(() => ElementFolder.GenerateElement("New Folder", Guid.NewGuid(), new List<string>(), true, this)))
|
||||
.Button("Track", () => CommandManager.ExecuteCreate(() => Track.GenerateElement("New Track", Guid.NewGuid(), new List<string>(), true, this)))
|
||||
.Button("Camera", () => CommandManager.ExecuteCreate(() => GameCamera.GenerateElement("New Camera", Guid.NewGuid(), new List<string>(), true, this, GameCamera.CameraViewType.Perspective, 60, 10)))
|
||||
.Button("Cross Track Point", () => CommandManager.ExecuteCreate(() => CrossTrackPoint.GenerateElement("New Cross Track Point", Guid.NewGuid(), new List<string>(), true, this, new FlexibleInt(), new FlexibleFloat())))
|
||||
.Build();
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Generate Elements", sectionOrder: 15)
|
||||
.Preset(InspectorBuilder.TransformPreset)
|
||||
.Section("Generate Notes", sectionOrder: 20)
|
||||
.Button("Tap", () => Tap.GenerateElement("New Tap", Guid.NewGuid(), new List<string>(), true, this, 0f))
|
||||
.Button("Stay", () => Stay.GenerateElement("New Stay", Guid.NewGuid(), new List<string>(), true, this, 0f))
|
||||
.Button("Hold", () => Hold.GenerateElement("New Hold", Guid.NewGuid(), new List<string>(), true, this, 0f, 1f))
|
||||
.Button("Flick", () => Flick.GenerateElement("New Flick", Guid.NewGuid(), new List<string>(), true, this, 0f, new List<Vector2>()))
|
||||
.Button("Tap", () => CommandManager.ExecuteCreate(() => Tap.GenerateElement("New Tap", Guid.NewGuid(), new List<string>(), true, this, 0f)))
|
||||
.Button("Stay", () => CommandManager.ExecuteCreate(() => Stay.GenerateElement("New Stay", Guid.NewGuid(), new List<string>(), true, this, 0f)))
|
||||
.Button("Hold", () => CommandManager.ExecuteCreate(() => Hold.GenerateElement("New Hold", Guid.NewGuid(), new List<string>(), true, this, 0f, 1f)))
|
||||
.Button("Flick", () => CommandManager.ExecuteCreate(() => Flick.GenerateElement("New Flick", Guid.NewGuid(), new List<string>(), true, this, 0f, new List<Vector2>())))
|
||||
.Section("Generate Environment", sectionOrder: 30)
|
||||
.Button("Environment Object", () => TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(), true, this))
|
||||
.Button("Time Effects Collection", () => TimeEffectsCollection.GenerateElement("New Time Effects Collection", Guid.NewGuid(),
|
||||
new List<string>(), true, this, 0))
|
||||
.Button("Environment Object", () => CommandManager.ExecuteCreate(() => TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(), true, this)))
|
||||
.Button("Time Effects Collection", () => CommandManager.ExecuteCreate(() => TimeEffectsCollection.GenerateElement("New Time Effects Collection", Guid.NewGuid(),
|
||||
new List<string>(), true, this, 0)))
|
||||
.Button("Particle Emitter", () =>
|
||||
{
|
||||
ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
|
||||
CommandManager.ExecuteCreate(() => ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
|
||||
this, "", "", false, 0, 1, ParticleSystemSimulationSpace.World,
|
||||
10, 5, 1, 1, true, Vector3.zero);
|
||||
10, 5, 1, 1, true, Vector3.zero));
|
||||
})
|
||||
|
||||
.Section("Tools", sectionOrder: 40)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -25,14 +26,14 @@ namespace Ichni.RhythmGame
|
||||
.Preset(InspectorBuilder.TransformPreset)
|
||||
.Section("Generate")
|
||||
.Button("Field of View", () =>
|
||||
CameraFieldOfView.GenerateElement("New Field of View", Guid.NewGuid(),
|
||||
CommandManager.ExecuteCreate(() => CameraFieldOfView.GenerateElement("New Field of View", Guid.NewGuid(),
|
||||
new List<string>(), true, this, new FlexibleFloat(new List<AnimatedFloat>
|
||||
{
|
||||
new AnimatedFloat(0f, 1f, 60f, 60f, AnimationCurveType.Linear)
|
||||
})))
|
||||
}))))
|
||||
.Button("Extension", () =>
|
||||
GameCameraExtension.GenerateElement("New Extension", Guid.NewGuid(),
|
||||
new List<string>(), true, this, 1000f))
|
||||
CommandManager.ExecuteCreate(() => GameCameraExtension.GenerateElement("New Extension", Guid.NewGuid(),
|
||||
new List<string>(), true, this, 1000f)))
|
||||
.Build();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Ichni.RhythmGame
|
||||
.OnChanged(() => inspectorMain.SetInspector(this))
|
||||
.Button("Generate", () =>
|
||||
{
|
||||
EditorManager.instance.operationManager.CopyPasteDeleteModule.DeleteElement(this);
|
||||
EditorManager.instance.operationManager.CopyPasteDeleteModule.DeleteElementRaw(this);
|
||||
inspectorMain.ClearInspector();
|
||||
SubstantialObject.GenerateElement(elementName, elementGuid, tags, true,
|
||||
themeBundleName, objectName, parentElement);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -84,9 +85,9 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
if (skyboxSubsetter == null)
|
||||
{
|
||||
SkyboxSubsetter.GenerateElement("New Skybox Subsetter", Guid.NewGuid(),
|
||||
CommandManager.ExecuteCreate(() => SkyboxSubsetter.GenerateElement("New Skybox Subsetter", Guid.NewGuid(),
|
||||
new List<string>(), true, this,
|
||||
new List<string>(), new List<string>(), new List<float>(), new List<float>());
|
||||
new List<string>(), new List<string>(), new List<float>(), new List<float>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -75,7 +76,7 @@ namespace Ichni.RhythmGame
|
||||
.Section("Note Visual")
|
||||
.Button("Generate Note Visual", () =>
|
||||
{
|
||||
TemporaryObject.GenerateElement("New Note Visual", Guid.NewGuid(), new List<string>(), true, this);
|
||||
CommandManager.ExecuteCreate(() => TemporaryObject.GenerateElement("New Note Visual", Guid.NewGuid(), new List<string>(), true, this));
|
||||
})
|
||||
.EnabledIf(() => noteVisual == null)
|
||||
.Build();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -38,13 +39,13 @@ namespace Ichni.RhythmGame
|
||||
|
||||
public void GenerateBaseColorChange()
|
||||
{
|
||||
BaseColorChange.GenerateElement("New Base Color Change", Guid.NewGuid(), new List<string>(), true,
|
||||
CommandManager.ExecuteCreate(() => BaseColorChange.GenerateElement("New Base Color Change", Guid.NewGuid(), new List<string>(), true,
|
||||
this,
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.r, colorSubmodule.originalBaseColor.r, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.g, colorSubmodule.originalBaseColor.g, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.b, colorSubmodule.originalBaseColor.b, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.a, colorSubmodule.originalBaseColor.a, animationCurveType: AnimationCurveType.Linear) })
|
||||
);
|
||||
));
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -36,19 +37,19 @@ namespace Ichni.RhythmGame
|
||||
.Toggle(nameof(MotionAngles), "Motion With Angles")
|
||||
.Section("Generate")
|
||||
.Button("Game Camera", () =>
|
||||
GameCamera.GenerateElement("New Game Camera", Guid.NewGuid(), new List<string>(),
|
||||
true, this, GameCamera.CameraViewType.Perspective, 60, 10))
|
||||
CommandManager.ExecuteCreate(() => GameCamera.GenerateElement("New Game Camera", Guid.NewGuid(), new List<string>(),
|
||||
true, this, GameCamera.CameraViewType.Perspective, 60, 10)))
|
||||
.Button("Trail", () =>
|
||||
Trail.GenerateElement("New Trail", Guid.NewGuid(), new List<string>(),
|
||||
CommandManager.ExecuteCreate(() => Trail.GenerateElement("New Trail", Guid.NewGuid(), new List<string>(),
|
||||
true, this, 1, true, 1,
|
||||
AnimationCurve.Constant(0, 1, 1), ColorExtensions.DefaultGradient(), "", ""))
|
||||
AnimationCurve.Constant(0, 1, 1), ColorExtensions.DefaultGradient(), "", "")))
|
||||
.Button("Environment Object", () =>
|
||||
TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(),
|
||||
true, this))
|
||||
CommandManager.ExecuteCreate(() => TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(),
|
||||
true, this)))
|
||||
.Button("Generate Particle Emitter", () =>
|
||||
ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
|
||||
CommandManager.ExecuteCreate(() => ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
|
||||
this, "", "", false, 0, 1, ParticleSystemSimulationSpace.World,
|
||||
10, 5, 1, 1, true, Vector3.zero))
|
||||
10, 5, 1, 1, true, Vector3.zero)))
|
||||
.Build();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -29,16 +30,16 @@ namespace Ichni.RhythmGame
|
||||
.OnChanged(() => trackPositioner.motion.rotationOffset = motionEulerAngles)
|
||||
.Section("Generate")
|
||||
.Button("Generate Trail", () =>
|
||||
Trail.GenerateElement("New Trail", Guid.NewGuid(), new List<string>(), true,
|
||||
CommandManager.ExecuteCreate(() => Trail.GenerateElement("New Trail", Guid.NewGuid(), new List<string>(), true,
|
||||
this, 1, true, 1,
|
||||
AnimationCurve.Constant(0, 1, 1), ColorExtensions.DefaultGradient(), "", ""))
|
||||
AnimationCurve.Constant(0, 1, 1), ColorExtensions.DefaultGradient(), "", "")))
|
||||
.Button("Environment Object", () =>
|
||||
TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(),
|
||||
true, this))
|
||||
CommandManager.ExecuteCreate(() => TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(),
|
||||
true, this)))
|
||||
.Button("Generate Particle Emitter", () =>
|
||||
ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
|
||||
CommandManager.ExecuteCreate(() => ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
|
||||
this, "", "", false, 0, 1, ParticleSystemSimulationSpace.World,
|
||||
10, 5, 1, 1, true, Vector3.zero))
|
||||
10, 5, 1, 1, true, Vector3.zero)))
|
||||
.Build();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -33,16 +34,16 @@ namespace Ichni.RhythmGame
|
||||
.Toggle(nameof(MotionAngles), "Motion With Angles")
|
||||
.Section("Generate")
|
||||
.Button("Generate Trail", () =>
|
||||
Trail.GenerateElement("New Trail", Guid.NewGuid(), new List<string>(), true,
|
||||
CommandManager.ExecuteCreate(() => Trail.GenerateElement("New Trail", Guid.NewGuid(), new List<string>(), true,
|
||||
this, 1, true, 1,
|
||||
AnimationCurve.Constant(0, 1, 1), ColorExtensions.DefaultGradient(), "", ""))
|
||||
AnimationCurve.Constant(0, 1, 1), ColorExtensions.DefaultGradient(), "", "")))
|
||||
.Button("Environment Object", () =>
|
||||
TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(),
|
||||
true, this))
|
||||
CommandManager.ExecuteCreate(() => TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(),
|
||||
true, this)))
|
||||
.Button("Generate Particle Emitter", () =>
|
||||
ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
|
||||
CommandManager.ExecuteCreate(() => ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
|
||||
this, "", "", false, 0, 1, ParticleSystemSimulationSpace.World,
|
||||
10, 5, 1, 1, true, Vector3.zero))
|
||||
10, 5, 1, 1, true, Vector3.zero)))
|
||||
.Build();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -27,7 +28,7 @@ namespace Ichni.RhythmGame
|
||||
.OnChanged(ClosePath)
|
||||
.Button("Generate Path Node", () =>
|
||||
{
|
||||
PathNode.GenerateElement("New Path Node", Guid.NewGuid(), new List<string>(), true, track, true);
|
||||
CommandManager.ExecuteCreate(() => PathNode.GenerateElement("New Path Node", Guid.NewGuid(), new List<string>(), true, track, true));
|
||||
})
|
||||
.Toggle(nameof(isShowingDisplay), "Show Display")
|
||||
.OnChanged(() => SetDisplay(isShowingDisplay))
|
||||
|
||||
@@ -14,8 +14,10 @@ namespace Ichni.RhythmGame
|
||||
/// </summary>
|
||||
/// <param name="unitPositionOffset">单位位置整体偏移</param>
|
||||
/// <param name="unitTimeOffset">单位时间偏移</param>
|
||||
/// <param name="unitRotationOffset">单位旋转偏移(欧拉角)</param>
|
||||
/// <param name="unitScaleOffset">单位缩放偏移</param>
|
||||
/// <param name="iteration">迭代次数,即产生几个粘贴的Track</param>
|
||||
private void QuickCopy(Vector3 unitPositionOffset, float unitTimeOffset, bool includeAnimations = true, int iteration = 1, bool MovingTrack = false)
|
||||
private void QuickCopy(Vector3 unitPositionOffset, float unitTimeOffset, bool includeAnimations = true, int iteration = 1, bool MovingTrack = false, Vector3 unitRotationOffset = default, Vector3 unitScaleOffset = default)
|
||||
{
|
||||
if (iteration <= 0) return;
|
||||
|
||||
@@ -23,23 +25,29 @@ namespace Ichni.RhythmGame
|
||||
cpd.CopyElement(this);
|
||||
for (int i = 1; i <= iteration; i++)
|
||||
{
|
||||
cpd.PasteElement(parentElement);
|
||||
cpd.PasteElementRaw(this, parentElement);
|
||||
Track newTrack = cpd.pastedElementList[0] as Track;
|
||||
Vector3 positionOffset = unitPositionOffset * i;
|
||||
float timeOffset = unitTimeOffset * i;
|
||||
Vector3 rotationOffset = unitRotationOffset * i;
|
||||
Vector3 scaleOffset = unitScaleOffset * i;
|
||||
|
||||
//以下:对Track的所有有效的Submodule和子GameElement进行偏移 TODO: 需要思考是否有统一时间偏移的方法?
|
||||
if (MovingTrack)
|
||||
{
|
||||
newTrack.transformSubmodule.originalPosition += positionOffset;
|
||||
newTrack.transformSubmodule.originalEulerAngles += rotationOffset;
|
||||
newTrack.transformSubmodule.originalScale += scaleOffset;
|
||||
newTrack.transformSubmodule.Refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
//PathNode,位置偏移
|
||||
//PathNode,位置/旋转/缩放偏移
|
||||
newTrack.trackPathSubmodule.pathNodeList.ForEach(pn =>
|
||||
{
|
||||
pn.transformSubmodule.originalPosition += positionOffset;
|
||||
pn.transformSubmodule.originalEulerAngles += rotationOffset;
|
||||
pn.transformSubmodule.originalScale += scaleOffset;
|
||||
pn.transformSubmodule.Refresh();
|
||||
});
|
||||
}
|
||||
@@ -161,4 +169,4 @@ namespace Ichni.RhythmGame
|
||||
trackPathSubmodule.pathNodeList.ForEach(pn => pn.SetPathNodeSphere(isShowing));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ichni.RhythmGame;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
@@ -79,41 +80,45 @@ namespace Ichni.RhythmGame
|
||||
.Section("Generate Elements", sectionOrder: 20)
|
||||
.Button("Path Node", () =>
|
||||
{
|
||||
PathNode.GenerateElement("New Path Node", Guid.NewGuid(), new List<string>(), true, this, true);
|
||||
CommandManager.ExecuteCreate(() => PathNode.GenerateElement("New Path Node", Guid.NewGuid(), new List<string>(), true, this, true));
|
||||
})
|
||||
.EnabledIf(() => trackPathSubmodule != null)
|
||||
.Button("Track Percent Point", () =>
|
||||
{
|
||||
var a = TrackPercentPoint.GenerateElement("New Track Percent Point", Guid.NewGuid(), new List<string>(), true, this, new FlexibleFloat());
|
||||
if (trackTimeSubmodule != null && trackTimeSubmodule is TrackTimeSubmoduleMovable trackTimeSubmoduleMovable)
|
||||
a.trackPercent.Add(
|
||||
new AnimatedFloat(trackTimeSubmoduleMovable.trackStartTime, trackTimeSubmoduleMovable.trackEndTime, 0, 1, AnimationCurveType.Linear));
|
||||
CommandManager.ExecuteCreate(() =>
|
||||
{
|
||||
var a = TrackPercentPoint.GenerateElement("New Track Percent Point", Guid.NewGuid(), new List<string>(), true, this, new FlexibleFloat());
|
||||
if (trackTimeSubmodule != null && trackTimeSubmodule is TrackTimeSubmoduleMovable trackTimeSubmoduleMovable)
|
||||
a.trackPercent.Add(
|
||||
new AnimatedFloat(trackTimeSubmoduleMovable.trackStartTime, trackTimeSubmoduleMovable.trackEndTime, 0, 1, AnimationCurveType.Linear));
|
||||
return a;
|
||||
});
|
||||
})
|
||||
.Button("Track Head Point", () =>
|
||||
{
|
||||
TrackHeadPoint.GenerateElement("New Track Head Point", Guid.NewGuid(), new List<string>(), true, this, false, Vector3.zero);
|
||||
CommandManager.ExecuteCreate(() => TrackHeadPoint.GenerateElement("New Track Head Point", Guid.NewGuid(), new List<string>(), true, this, false, Vector3.zero));
|
||||
})
|
||||
.EnabledIf(() => trackTimeSubmodule is TrackTimeSubmoduleMovable)
|
||||
.Button("Tap", () => Tap.GenerateElement("New Tap", Guid.NewGuid(), new List<string>(), true, this, 0f))
|
||||
.Button("Stay", () => Stay.GenerateElement("New Stay", Guid.NewGuid(), new List<string>(), true, this, 0f))
|
||||
.Button("Hold", () => Hold.GenerateElement("New Hold", Guid.NewGuid(), new List<string>(), true, this, 0f, 1f))
|
||||
.Button("Flick", () => Flick.GenerateElement("New Flick", Guid.NewGuid(), new List<string>(), true, this, 0f, new List<Vector2>()))
|
||||
.Button("Tap", () => CommandManager.ExecuteCreate(() => Tap.GenerateElement("New Tap", Guid.NewGuid(), new List<string>(), true, this, 0f)))
|
||||
.Button("Stay", () => CommandManager.ExecuteCreate(() => Stay.GenerateElement("New Stay", Guid.NewGuid(), new List<string>(), true, this, 0f)))
|
||||
.Button("Hold", () => CommandManager.ExecuteCreate(() => Hold.GenerateElement("New Hold", Guid.NewGuid(), new List<string>(), true, this, 0f, 1f)))
|
||||
.Button("Flick", () => CommandManager.ExecuteCreate(() => Flick.GenerateElement("New Flick", Guid.NewGuid(), new List<string>(), true, this, 0f, new List<Vector2>())))
|
||||
.Button("Particle Tracker", () =>
|
||||
{
|
||||
ParticleTracker.GenerateElement("New Particle Tracker", Guid.NewGuid(), new List<string>(), true, this,
|
||||
string.Empty, string.Empty, false, 0, 1, false, 10, Vector3.right, 10, 5, true, Vector3.zero);
|
||||
CommandManager.ExecuteCreate(() => ParticleTracker.GenerateElement("New Particle Tracker", Guid.NewGuid(), new List<string>(), true, this,
|
||||
string.Empty, string.Empty, false, 0, 1, false, 10, Vector3.right, 10, 5, true, Vector3.zero));
|
||||
})
|
||||
.Button("Object Tracker", () =>
|
||||
{
|
||||
ObjectTracker.GenerateElement("New Object Tracker", Guid.NewGuid(), new List<string>(), true, this,
|
||||
CommandManager.ExecuteCreate(() => ObjectTracker.GenerateElement("New Object Tracker", Guid.NewGuid(), new List<string>(), true, this,
|
||||
string.Empty, string.Empty, 10, Vector2.zero, Vector2.zero, string.Empty,
|
||||
false, Vector3.zero, Vector3.zero, string.Empty,
|
||||
false, Vector3.zero, Vector3.zero, string.Empty);
|
||||
false, Vector3.zero, Vector3.zero, string.Empty));
|
||||
})
|
||||
.Button("Track Global Color Change", () =>
|
||||
{
|
||||
TrackGlobalColorChange.GenerateElement("New Track Global Color Change", Guid.NewGuid(), new List<string>(), true, this,
|
||||
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true));
|
||||
CommandManager.ExecuteCreate(() => TrackGlobalColorChange.GenerateElement("New Track Global Color Change", Guid.NewGuid(), new List<string>(), true, this,
|
||||
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true)));
|
||||
})
|
||||
.Build();
|
||||
|
||||
@@ -126,22 +131,44 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
IHaveInspection qcWindow = inspectorMain.GenerateSecondaryWindow(this, elementName + "'s Quick Copy");
|
||||
var qcContainer = qcWindow.GenerateContainer();
|
||||
var qcSubcontainer = qcContainer.GenerateSubcontainer(3);
|
||||
var xField = qcWindow.GenerateInputField(qcSubcontainer, "X offset", "0");
|
||||
var yField = qcWindow.GenerateInputField(qcSubcontainer, "Y offset", "0");
|
||||
var zField = qcWindow.GenerateInputField(qcSubcontainer, "Z offset", "0");
|
||||
var timeField = qcWindow.GenerateInputField(qcSubcontainer, "Time offset", "0");
|
||||
var iterationField = qcWindow.GenerateInputField(qcSubcontainer, "Iteration", "0");
|
||||
var includeAnimationToggle = qcWindow.GenerateToggle(null, qcSubcontainer, "Include Animation", string.Empty);
|
||||
var movingTrackToggle = qcWindow.GenerateToggle(null, qcSubcontainer, "Moving Track or PathNode", string.Empty);
|
||||
qcWindow.GenerateButton(this, qcSubcontainer, "Copy", () =>
|
||||
|
||||
// 位置偏移
|
||||
var posSub = qcContainer.GenerateSubcontainer(3);
|
||||
var xField = qcWindow.GenerateInputField(posSub, "X offset", "0");
|
||||
var yField = qcWindow.GenerateInputField(posSub, "Y offset", "0");
|
||||
var zField = qcWindow.GenerateInputField(posSub, "Z offset", "0");
|
||||
|
||||
// 旋转偏移(欧拉角)
|
||||
var rotSub = qcContainer.GenerateSubcontainer(3);
|
||||
var rotXField = qcWindow.GenerateInputField(rotSub, "Rot X", "0");
|
||||
var rotYField = qcWindow.GenerateInputField(rotSub, "Rot Y", "0");
|
||||
var rotZField = qcWindow.GenerateInputField(rotSub, "Rot Z", "0");
|
||||
|
||||
// 缩放偏移
|
||||
var scaleSub = qcContainer.GenerateSubcontainer(3);
|
||||
var scaleXField = qcWindow.GenerateInputField(scaleSub, "Scale X", "0");
|
||||
var scaleYField = qcWindow.GenerateInputField(scaleSub, "Scale Y", "0");
|
||||
var scaleZField = qcWindow.GenerateInputField(scaleSub, "Scale Z", "0");
|
||||
|
||||
// 时间 & 迭代
|
||||
var timeSub = qcContainer.GenerateSubcontainer(3);
|
||||
var timeField = qcWindow.GenerateInputField(timeSub, "Time offset", "0");
|
||||
var iterationField = qcWindow.GenerateInputField(timeSub, "Iteration", "1");
|
||||
|
||||
// 选项 & 按钮
|
||||
var toggleSub = qcContainer.GenerateSubcontainer(3);
|
||||
var includeAnimationToggle = qcWindow.GenerateToggle(null, toggleSub, "Include Animation", string.Empty);
|
||||
var movingTrackToggle = qcWindow.GenerateToggle(null, toggleSub, "Move Track", string.Empty);
|
||||
qcWindow.GenerateButton(this, toggleSub, "Copy", () =>
|
||||
{
|
||||
Vector3 positionOffset = new Vector3(xField.GetValue<float>(), yField.GetValue<float>(), zField.GetValue<float>());
|
||||
Vector3 rotationOffset = new Vector3(rotXField.GetValue<float>(), rotYField.GetValue<float>(), rotZField.GetValue<float>());
|
||||
Vector3 scaleOffset = new Vector3(scaleXField.GetValue<float>(), scaleYField.GetValue<float>(), scaleZField.GetValue<float>());
|
||||
float timeOffset = timeField.GetValue<float>();
|
||||
int iteration = iterationField.GetValue<int>();
|
||||
bool includeAnimation = includeAnimationToggle.toggle.isOn;
|
||||
bool movingTrack = movingTrackToggle.toggle.isOn;
|
||||
this.QuickCopy(positionOffset, timeOffset, includeAnimation, iteration, movingTrack);
|
||||
this.QuickCopy(positionOffset, timeOffset, includeAnimation, iteration, movingTrack, rotationOffset, scaleOffset);
|
||||
});
|
||||
})
|
||||
.Button("Whole Track Move", () =>
|
||||
@@ -198,7 +225,7 @@ namespace Ichni.RhythmGame
|
||||
.Span(3)
|
||||
.Button("Fast Note Tracker", () =>
|
||||
{
|
||||
FastNoteTracker.GenerateElement("Fast Note Tracker", Guid.NewGuid(), new List<string>(), true, this);
|
||||
CommandManager.ExecuteCreate(() => FastNoteTracker.GenerateElement("Fast Note Tracker", Guid.NewGuid(), new List<string>(), true, this));
|
||||
})
|
||||
.Span(3)
|
||||
.Build();
|
||||
@@ -225,7 +252,7 @@ namespace Ichni.RhythmGame
|
||||
|
||||
return notes;
|
||||
}
|
||||
|
||||
|
||||
[Button("Check Notes")]
|
||||
public void checkNotes()
|
||||
{
|
||||
@@ -252,7 +279,7 @@ namespace Ichni.RhythmGame
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Button("Rebuild")]
|
||||
public void Rebuild()
|
||||
{
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Ichni.RhythmGame;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
@@ -126,9 +127,9 @@ namespace Ichni.Editor
|
||||
copiedElement = gameElement;
|
||||
}
|
||||
|
||||
public void PasteElement(GameElement parentElement)
|
||||
{
|
||||
if (parentElement == null)
|
||||
public void PasteElement(GameElement parentElement)
|
||||
{
|
||||
if (parentElement == null)
|
||||
{
|
||||
LogWindow.Log("No parent element selected to paste.", Color.red);
|
||||
return;
|
||||
@@ -137,44 +138,73 @@ namespace Ichni.Editor
|
||||
if (copiedElement == null)
|
||||
{
|
||||
LogWindow.Log("No element copied.");
|
||||
return;
|
||||
}
|
||||
|
||||
LogWindow.Log("Pasted element: " + copiedElement.elementName + " to " + parentElement.elementName);
|
||||
pastedElementList = new List<GameElement>();
|
||||
AffiliatedPaste(copiedElement, parentElement);
|
||||
|
||||
// 粘贴完成后,对所有新生成的元素执行 AfterInitialize 和 Refresh,
|
||||
// 与 EditorManager.LoadProject 的加载后流程对齐,确保 Manager 注册等关键步骤不遗漏。
|
||||
return;
|
||||
}
|
||||
|
||||
CommandManager.ExecuteCommand(new PasteElementCommand(this, copiedElement, parentElement));
|
||||
}
|
||||
|
||||
public GameElement PasteElementRaw(GameElement sourceElement, GameElement parentElement)
|
||||
{
|
||||
if (sourceElement == null || parentElement == null) return null;
|
||||
|
||||
LogWindow.Log("Pasted element: " + sourceElement.elementName + " to " + parentElement.elementName);
|
||||
pastedElementList = new List<GameElement>();
|
||||
AffiliatedPaste(sourceElement, parentElement);
|
||||
|
||||
// 粘贴完成后,对所有新生成的元素执行 AfterInitialize 和 Refresh,
|
||||
// 与 EditorManager.LoadProject 的加载后流程对齐,确保 Manager 注册等关键步骤不遗漏。
|
||||
foreach (GameElement pasted in pastedElementList)
|
||||
{
|
||||
if (pasted == null) continue;
|
||||
pasted.AfterInitialize();
|
||||
pasted.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteElement(GameElement gameElement)
|
||||
pasted.AfterInitialize();
|
||||
pasted.Refresh();
|
||||
}
|
||||
|
||||
return pastedElementList.FirstOrDefault();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CommandManager.ExecuteCommand(new DeleteElementCommand(gameElement));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
EditorManager.instance.operationManager.RemoveSelectElement(gameElement);
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用递归的方式复制粘贴物体及其所有子物体
|
||||
|
||||
@@ -230,9 +230,15 @@ namespace Ichni
|
||||
|
||||
public class BeatmapClipManager
|
||||
{
|
||||
private string clipFolder => Application.streamingAssetsPath + "/Clips";
|
||||
private string GetClipPath(string clipName) => clipFolder + "/" + clipName + ".json";
|
||||
|
||||
public void SaveClip(string clipName)
|
||||
{
|
||||
LogWindow.Log("Start Saving Clip...");
|
||||
clipName = clipName?.Trim();
|
||||
|
||||
if (!ValidateClipName(clipName)) return;
|
||||
|
||||
if (EditorManager.instance.operationManager.currentSelectedElements.Count != 1) // TODO: 后续适应多选
|
||||
{
|
||||
@@ -256,8 +262,11 @@ namespace Ichni
|
||||
public void LoadClip(string clipName)
|
||||
{
|
||||
LogWindow.Log("Start Loading Clip...");
|
||||
clipName = clipName?.Trim();
|
||||
|
||||
if (!ES3.FileExists(Application.streamingAssetsPath + "/Clips/" + clipName + ".json"))
|
||||
if (!ValidateClipName(clipName)) return;
|
||||
|
||||
if (!ES3.FileExists(GetClipPath(clipName)))
|
||||
{
|
||||
LogWindow.Log("Clip not found", Color.red);
|
||||
return;
|
||||
@@ -278,9 +287,10 @@ namespace Ichni
|
||||
}
|
||||
Debug.Log(selectedElement.elementName + " " + selectedElement.elementGuid);
|
||||
|
||||
_LoadClip(selectedElement, clipName);
|
||||
|
||||
LogWindow.Log("Load Clip Complete", Color.green);
|
||||
if (_LoadClip(selectedElement, clipName))
|
||||
{
|
||||
LogWindow.Log("Load Clip Complete", Color.green);
|
||||
}
|
||||
}
|
||||
|
||||
private void _SaveClip(GameElement element, string clipName)
|
||||
@@ -290,7 +300,8 @@ namespace Ichni
|
||||
element.GetAllGameElementsFromThis().ForEach(e =>
|
||||
{
|
||||
e.SaveBM();
|
||||
clip.Add(e.matchedBM);
|
||||
if (e.matchedBM != null)
|
||||
clip.Add(e.matchedBM);
|
||||
e.submoduleList.ForEach(s =>
|
||||
{
|
||||
s.SaveBM();
|
||||
@@ -299,47 +310,59 @@ namespace Ichni
|
||||
});
|
||||
});
|
||||
|
||||
string filePath = Application.streamingAssetsPath + "/Clips/" + clipName + ".json";
|
||||
Directory.CreateDirectory(clipFolder);
|
||||
string filePath = GetClipPath(clipName);
|
||||
ES3.Save("Clip", clip, filePath, ProjectManager.SaveSettings);
|
||||
}
|
||||
|
||||
private void _LoadClip(GameElement target, string clipName)
|
||||
private bool _LoadClip(GameElement target, string clipName)
|
||||
{
|
||||
try
|
||||
{
|
||||
string filePath = Application.streamingAssetsPath + "/Clips/" + clipName + ".json";
|
||||
string filePath = GetClipPath(clipName);
|
||||
List<BaseElement_BM> clip = ES3.Load<List<BaseElement_BM>>("Clip", filePath, ProjectManager.SaveSettings);
|
||||
|
||||
if (clip == null || clip.Count == 0)
|
||||
{
|
||||
Debug.LogError("Clip is empty or null");
|
||||
return;
|
||||
LogWindow.Log("Clip is empty or null", Color.red);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证第一个元素
|
||||
if (!(clip[0] is GameElement_BM first))
|
||||
{
|
||||
Debug.LogError("First element is not a GameElement_BM");
|
||||
return;
|
||||
LogWindow.Log("First element is not a GameElement_BM", Color.red);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 处理目标对象 - 添加清理机制
|
||||
target.SaveBM();
|
||||
if (target.matchedBM is not GameElement_BM targetBM)
|
||||
{
|
||||
LogWindow.Log("Load Clip failed: target did not create a valid BM.", Color.red);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool targetAdded = GameElement_BM.identifier.TryAdd(target.elementGuid, target.matchedBM as GameElement_BM);
|
||||
if (!targetAdded)
|
||||
{
|
||||
Debug.LogWarning("Target element already exists in identifier dictionary");
|
||||
}
|
||||
targetBM.matchedElement = target;
|
||||
|
||||
List<GameElement> loadedElements = new List<GameElement>();
|
||||
|
||||
// 处理第一个元素及其附加元素
|
||||
ProcessGameElement(first, clip, target.elementGuid);
|
||||
if (!ProcessGameElement(first, clip, target.elementGuid, loadedElements)) return false;
|
||||
|
||||
// 处理后续元素
|
||||
for (var index = 1; index < clip.Count; index++)
|
||||
{
|
||||
if (clip[index] is GameElement_BM gameElement)
|
||||
{
|
||||
ProcessGameElement(gameElement, clip, null);
|
||||
if (!ProcessGameElement(gameElement, clip, null, loadedElements)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -348,14 +371,28 @@ namespace Ichni
|
||||
}
|
||||
}
|
||||
|
||||
EditorManager.instance.beatmapContainer.ExecuteLowPriorityActions();
|
||||
loadedElements.ForEach(element =>
|
||||
{
|
||||
if (element == null) return;
|
||||
element.AfterInitialize();
|
||||
element.Refresh();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"Failed to load clip: {ex.Message}");
|
||||
LogWindow.Log("Failed to load clip: " + ex.Message, Color.red);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessGameElement(GameElement_BM gameElement, List<BaseElement_BM> clip, Guid? attachToGuid)
|
||||
private bool ProcessGameElement(
|
||||
GameElement_BM gameElement,
|
||||
List<BaseElement_BM> clip,
|
||||
Guid? attachToGuid,
|
||||
List<GameElement> loadedElements)
|
||||
{
|
||||
List<BaseElement_BM> attachedElements = GameElement_BM.GetAllAttachedBaseElements(gameElement, clip);
|
||||
|
||||
@@ -365,7 +402,8 @@ namespace Ichni
|
||||
if (!elementAdded)
|
||||
{
|
||||
Debug.LogError($"Failed to add element with GUID: {gameElement.elementGuid}");
|
||||
return;
|
||||
LogWindow.Log("Failed to add clip element: " + gameElement.elementName, Color.red);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 更新附加元素
|
||||
@@ -381,7 +419,31 @@ namespace Ichni
|
||||
}
|
||||
|
||||
gameElement.ExecuteBM();
|
||||
if (gameElement.matchedElement == null)
|
||||
{
|
||||
LogWindow.Log("Failed to generate clip element: " + gameElement.elementName, Color.red);
|
||||
return false;
|
||||
}
|
||||
|
||||
loadedElements.Add(gameElement.matchedElement);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ValidateClipName(string clipName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(clipName))
|
||||
{
|
||||
LogWindow.Log("Clip name cannot be empty.", Color.red);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (clipName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
|
||||
{
|
||||
LogWindow.Log("Clip name contains invalid characters.", Color.red);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user