Files
ichni_Creator_Studio/Assets/Scripts/CommandSystem/ChangeValueCommand.cs
SoulliesOfficial 11423add8f shapes
2026-03-26 14:48:04 -04:00

85 lines
2.9 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.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using Ichni.RhythmGame;
namespace Ichni.Editor.Commands
{
public class ChangeValueCommand : ICommand
{
private IBaseElement target;
private string path;
private object oldValue;
private object newValue;
private float timestamp;
// 合并窗口期:同一字段 1 秒内的接连覆盖,只算作一次编辑行为
private const float MERGE_WINDOW = 1f;
public ChangeValueCommand(IBaseElement target, string path, object newValue)
{
this.target = target;
this.path = path;
this.newValue = newValue;
this.oldValue = ReflectionHelper.GetDeepValue(target, path);
this.timestamp = Time.realtimeSinceStartup;
}
public void Execute()
{
if (target == null) return;
ReflectionHelper.SetDeepValue(target, path, newValue);
}
public void Undo()
{
// 防暴毙机制:如果所附着的对象因为其它原因在场景中已被销毁(如删除该 Note自动拦截撤销并停止访问底层数据。
if (target == null) return;
ReflectionHelper.SetDeepValue(target, path, oldValue);
target.Refresh();
}
public void Redo()
{
if (target == null) return;
ReflectionHelper.SetDeepValue(target, path, newValue);
target.Refresh();
}
public bool TryMerge(ICommand other)
{
if (other is ChangeValueCommand otherCommand)
{
// 若对象、路径完全一致,则尝试吞并它的新值
if (System.Object.ReferenceEquals(this.target, otherCommand.target) &&
this.path == otherCommand.path &&
(otherCommand.timestamp - this.timestamp) < MERGE_WINDOW)
{
this.newValue = otherCommand.newValue;
this.timestamp = otherCommand.timestamp;
return true;
}
}
return false;
}
private void RefreshInspectorIfMatched()
{
var inspector = EditorManager.instance.uiManager.inspector;
if (inspector != null && inspector.connectedGameElement != null)
{
// 由于目前 DynamicUI 未实现细粒度的数据绑定事件派发,发生撤回时,我们重新装载选择一次右侧属性窗面板以完成显示同步。
// 借由我们之前的对象池机制,这个 SetInspector 消耗会在低于 1ms 的时间内无感重构。
inspector.SetInspector(inspector.connectedGameElement);
}
}
}
}