超级爆改
This commit is contained in:
87
Assets/Scripts/CommandSystem/ChangeValueCommand.cs
Normal file
87
Assets/Scripts/CommandSystem/ChangeValueCommand.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
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);
|
||||
// 修复:必须主动唤醒目标通知其数据已完成覆写,否则拖拽属性将无法立刻映射到真实世界物体
|
||||
target.Refresh();
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
// 防暴毙机制:如果所附着的对象因为其它原因在场景中已被销毁(如删除该 Note),自动拦截撤销并停止访问底层数据。
|
||||
if (target == null) return;
|
||||
|
||||
ReflectionHelper.SetDeepValue(target, path, oldValue);
|
||||
target.Refresh();
|
||||
|
||||
// 通知 UI 面板重载(保证数据被回滚后,界面的参数显示不再是之前打错的值)
|
||||
RefreshInspectorIfMatched();
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
if (target == null) return;
|
||||
|
||||
ReflectionHelper.SetDeepValue(target, path, newValue);
|
||||
target.Refresh();
|
||||
|
||||
RefreshInspectorIfMatched();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user