Files
ichni_Creator_Studio/Assets/Scripts/Console/EditorConsoleMethods.cs

903 lines
38 KiB
C#
Raw Normal View History

2025-06-09 12:42:23 +08:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
2025-10-18 15:58:55 +08:00
using System.Threading.Tasks;
2025-06-09 12:42:23 +08:00
using Ichni.RhythmGame;
using Ichni.RhythmGame.Beatmap;
using Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse;
using UniRx;
2025-06-09 12:42:23 +08:00
using UnityEngine;
namespace Ichni.Editor
{
public static class EditorConsoleMethods
{
public static Inspector inspector => EditorManager.instance.uiManager.inspector;
public static Hierarchy hierarchy => EditorManager.instance.uiManager.hierarchy;
public static LogWindow logWindow => EditorManager.instance.uiManager.mainPage.logWindow;
public static void tp(Vector3 pos)
{
if (EditorManager.instance.cameraManager.isSceneCameraActive)
{
EditorManager.instance.cameraManager.sceneCamera.sceneCamera.transform.position = pos;
}
}
// 保留无参tp
public static void tp()
{
if (EditorManager.instance.cameraManager.isSceneCameraActive)
{
EditorManager.instance.cameraManager.sceneCamera.sceneCamera.transform.position =
inspector.connectedGameElement.transform.position;
}
}
public static void ReName(string message)
{
inspector.connectedGameElement.elementName = message;
inspector.connectedGameElement.Refresh();
}
public static void Lgp(int loop, Vector3 start, Vector3 end, bool Clear = false, bool offsetOrigin = false)
2025-06-09 12:42:23 +08:00
{
if (inspector.connectedGameElement == null || inspector.connectedGameElement.GetType() != typeof(Track))
{
LogWindow.Log("Please select a Track first!");
return;
}
if (loop <= 1)
{
LogWindow.Log("Loop must be greater than 1!");
return;
}
2025-06-09 12:42:23 +08:00
Track track = (Track)inspector.connectedGameElement;
List<PathNode> oldNodes = track.trackPathSubmodule.pathNodeList.ToList();
List<PathNode> newNodes = new List<PathNode>();
// 如果 Clear 且有旧节点,迁移变换
if (Clear)
{
if (offsetOrigin && oldNodes.Count > 0 && newNodes.Count > 0)
{
AdjustPathNodesToNearest(track, newNodes, oldNodes);
}
// 清除之前的PathNode
foreach (var node in oldNodes)
{
EditorManager.instance.operationManager.CopyPasteDeleteModule.DeleteElement(node);
}
}
2025-06-09 12:42:23 +08:00
for (int i = 0; i < loop; i++)
{
float t = (float)i / (loop - 1); // 修正插值
2025-06-09 12:42:23 +08:00
float x = start.x + (end.x - start.x) * t;
float y = start.y + (end.y - start.y) * t;
float z = start.z + (end.z - start.z) * t;
PathNode j = PathNode.GenerateElement("PathNode" + i.ToString(), Guid.NewGuid(), new List<string>(), true, track, true);
j.transformSubmodule.originalPosition = new Vector3(x, y, z);
newNodes.Add(j);
}
}
/// <summary>
/// 将原有 PathNode 的变换(位置、旋转、缩放)迁移到新生成的最近 PathNode 上
/// </summary>
public static bool AdjustPathNodesToNearest(Track track, List<PathNode> newNodes, List<PathNode> oldNodes)
{
foreach (var oldNode in oldNodes)
{
// 找到距离 oldNode 最近的新节点
PathNode nearest = newNodes
.OrderBy(n => Vector3.Distance(n.transformSubmodule.originalPosition, oldNode.transformSubmodule.originalPosition))
.FirstOrDefault();
if (nearest != null)
{
// 计算 oldNode 的变换(直接用欧拉角,不用四元数)
Vector3 deltaPos = oldNode.transformSubmodule.originalPosition - oldNode.transformSubmodule.originalPosition;
Vector3 deltaEuler = oldNode.transformSubmodule.originalEulerAngles - oldNode.transformSubmodule.originalEulerAngles;
Vector3 deltaScale = oldNode.transformSubmodule.originalScale - oldNode.transformSubmodule.originalScale;
// 将变换应用到新节点
nearest.transformSubmodule.originalPosition += deltaPos;
nearest.transformSubmodule.originalEulerAngles += deltaEuler;
nearest.transformSubmodule.originalScale += deltaScale;
}
2025-06-09 12:42:23 +08:00
}
return true;
2025-06-09 12:42:23 +08:00
}
// 支持主轴方向的螺旋线式 PathNode
public static void Spiral(int loop, Vector3 center, float r, float h, int pointsPerTurn, string axis = "y")
{
if (inspector.connectedGameElement == null || inspector.connectedGameElement.GetType() != typeof(Track))
{
LogWindow.Log("Please select a Track first!");
return;
}
Track track = (Track)inspector.connectedGameElement;
for (int i = 0; i < loop; i++)
{
float t = (float)i / loop;
float angle = 2 * Mathf.PI * (i % pointsPerTurn) / pointsPerTurn;
Vector3 pos = new Vector3(center.x, center.y, center.z);
switch (axis.ToLower())
{
case "x":
pos.x += h * t;
pos.y += r * Mathf.Cos(angle);
pos.z += r * Mathf.Sin(angle);
break;
case "y":
pos.x += r * Mathf.Cos(angle);
pos.y += h * t;
pos.z += r * Mathf.Sin(angle);
break;
case "z":
pos.x += r * Mathf.Cos(angle);
pos.y += r * Mathf.Sin(angle);
pos.z += h * t;
break;
default:
pos.x += r * Mathf.Cos(angle);
pos.y += h * t;
pos.z += r * Mathf.Sin(angle);
break;
}
PathNode node = PathNode.GenerateElement("SpiralNode" + i.ToString(), Guid.NewGuid(), new List<string>(), true, track, true);
node.transformSubmodule.originalPosition = pos;
}
}
// 任意方向的螺旋线式 PathNode中心点和方向均为Vector3
public static void Spiral(int loop, Vector3 center, float r, float h, int pointsPerTurn, Vector3 dir)
{
if (inspector.connectedGameElement == null || inspector.connectedGameElement.GetType() != typeof(Track))
{
LogWindow.Log("Please select a Track first!");
return;
}
Vector3 direction = dir.normalized;
if (direction == Vector3.zero) direction = Vector3.up; // 默认Y轴
Quaternion rot = Quaternion.FromToRotation(Vector3.up, direction);
Track track = (Track)inspector.connectedGameElement;
for (int i = 0; i < loop; i++)
{
float t = (float)i / loop;
float angle = 2 * Mathf.PI * (i % pointsPerTurn) / pointsPerTurn;
Vector3 localPos = new Vector3(
r * Mathf.Cos(angle),
h * t,
r * Mathf.Sin(angle)
);
Vector3 pos = center + rot * localPos;
PathNode node = PathNode.GenerateElement("SpiralNode" + i.ToString(), Guid.NewGuid(), new List<string>(), true, track, true);
node.transformSubmodule.originalPosition = pos;
}
}
public static void DelSameInParent()
{
Type type = inspector.connectedGameElement.GetType();
for (int i = inspector.connectedGameElement.parentElement.childElementList.Count - 1; i >= 0; i--)
{
GameElement element = inspector.connectedGameElement.parentElement.childElementList[i];
if (element.GetType() == type && element != inspector.connectedGameElement)
{
EditorManager.instance.operationManager.CopyPasteDeleteModule.DeleteElement(element);
}
}
EditorManager.instance.operationManager.CopyPasteDeleteModule.DeleteElement(inspector.connectedGameElement);
}
public static void SamplerImport(string inputData)
{
if (!EditorManager.instance.useNotePrefab)
{
LogWindow.Log("Pleasee nable \"Note Prefab\" in EditorManager", Color.red);
return;
}
// 改进的正则表达式支持5个字段和负数
Regex dataPattern = new Regex(
@"\(\s*([^,]+?)\s*,\s*([^,]+?)\s*,\s*([-+]?\d*\.?\d+)\s*,\s*([-+]?\d*\.?\d+)\s*(?:,\s*([-+]?\d*\.?\d+)\s*)?\)",
RegexOptions.Compiled
);
Debug.Log("===== =====");
MatchCollection matches = dataPattern.Matches(inputData);
Debug.Log($": {matches.Count}");
int recordCount = 1;
Track findTrack(string Findtext)
{
List<Track> tracks = EditorManager.instance.beatmapContainer.gameElementList.OfType<Track>().Where(i => i.elementName == Findtext).ToList();
if (tracks.Count == 0)
{
Debug.LogError($"未找到名为 {Findtext} 的轨道");
return null;
}
else if (tracks.Count > 1)
{
LogWindow.Log($"Repeat Track Of {Findtext}, please Cautious", Color.yellow);
}
return tracks[0];
}
foreach (Match match in matches)
{
if (match.Success)
{
string action = match.Groups[1].Value.Trim();
string id = match.Groups[2].Value.Trim();
// 解析公共字段
float timestamp = float.Parse(match.Groups[3].Value);
float value = float.Parse(match.Groups[4].Value);
// 处理Hold操作的特殊字段
float holdDuration = 0f;
bool isHold = false;
if (action == "Hold" && match.Groups[5].Success)
{
isHold = true;
holdDuration = float.Parse(match.Groups[5].Value);
}
// 构建输出信息
string logEntry = $"[记录#{recordCount++}] " +
$"Note: {action.PadRight(5)} | " +
$"ID: {id} | " +
$"时间: {timestamp.ToString("0.000").PadLeft(7)} | " +
$"X值: {value.ToString("0.000").PadLeft(7)}";
if (isHold)
{
logEntry += $" | 持续时间: {holdDuration.ToString("0.000")}";
}
Debug.Log(logEntry);
if (findTrack(id) is null)
{
Debug.LogError($"未找到名为 {id} 的轨道");
continue;
}
// 根据动作类型处理
switch (action)
{
case "Tap":
Tap a = Tap.GenerateElement("New Tap", Guid.NewGuid(), new List<string>(), true, findTrack(id), timestamp);
2025-06-09 12:42:23 +08:00
((TransformSubmodule)a.noteVisual.submoduleList.Where(i => i is TransformSubmodule)?.First()).originalPosition = new Vector3(value, 0, 0);
2025-06-09 13:49:17 +08:00
a.noteVisual.SetEditorSubmodules(); // 设置selset
2025-06-09 12:42:23 +08:00
a.Refresh();
break;
case "Stay":
Stay b = Stay.GenerateElement("New Stay", Guid.NewGuid(), new List<string>(), true, findTrack(id), timestamp);
2025-06-09 12:42:23 +08:00
((TransformSubmodule)b.noteVisual.submoduleList.Where(i => i is TransformSubmodule)?.First()).originalPosition = new Vector3(value, 0, 0);
2025-06-09 13:49:17 +08:00
b.noteVisual.SetEditorSubmodules(); // 设置selset
2025-06-09 12:42:23 +08:00
b.Refresh();
break;
case "Hold":
Hold c = Hold.GenerateElement("New Hold", Guid.NewGuid(), new List<string>(), true, findTrack(id), timestamp, timestamp + holdDuration);
2025-06-09 12:42:23 +08:00
((TransformSubmodule)c.noteVisual.submoduleList.Where(i => i is TransformSubmodule)?.First()).originalPosition = new Vector3(value, 0, 0);
2025-06-09 13:49:17 +08:00
c.noteVisual.SetEditorSubmodules(); // 设置selset
2025-06-09 12:42:23 +08:00
c.Refresh();
break;
case "Flick":
Flick d = Flick.GenerateElement("New Flick", Guid.NewGuid(), new List<string>(), true, findTrack(id), timestamp, new List<Vector2>());
2025-06-09 12:42:23 +08:00
((TransformSubmodule)d.noteVisual.submoduleList.Where(i => i is TransformSubmodule)?.First()).originalPosition = new Vector3(value, 0, 0);
2025-06-09 13:49:17 +08:00
d.noteVisual.SetEditorSubmodules(); // 设置selset
2025-06-09 12:42:23 +08:00
d.Refresh();
break;
default:
Debug.LogError($"未知类型: {action}");
break;
}
}
}
Debug.Log("===== =====");
}
2025-06-14 20:47:45 +08:00
public static void SetNoteHLInGame(bool forceSetOff = false, bool SameTheme = false)
{
var noteBases = EditorManager.instance.beatmapContainer.gameElementList.OfType<NoteBase>().ToList();
// 先全部关闭高亮如果forceSetOff为true
if (forceSetOff)
{
foreach (var note in noteBases)
{
if (note.noteVisual != null)
{
note.noteVisual.isHighlighted = false;
try
{
note.noteVisual?.SetHighlight();
}
catch (Exception ex)
{
Debug.LogError($"Error setting highlight for note {note.name}: {ex.Message}");
}
}
2025-06-14 20:47:45 +08:00
}
}
// 按时间分组
var groups = SameTheme
? noteBases.GroupBy(n => (object)new { n.exactJudgeTime, Type = n.GetType() })
: noteBases.GroupBy(n => (object)n.exactJudgeTime);
foreach (var group in groups)
{
if (group.Count() > 1)
{
foreach (var note in group)
{
if (note.noteVisual != null)
{
note.noteVisual.isHighlighted = true;
try
{
note.noteVisual?.SetHighlight();
}
catch (Exception ex)
{
Debug.LogError($"Error setting highlight for note {note.name}: {ex.Message}");
}
}
2025-06-14 20:47:45 +08:00
}
}
}
}
public static void SetNoteHLInElement(bool forceSetOff = false, bool SameTheme = false)
{
var noteBases = inspector.connectedGameElement.GetAllGameElementsFromThis().OfType<NoteBase>().ToList();
// 先全部关闭高亮如果forceSetOff为true
if (forceSetOff)
{
foreach (var note in noteBases)
{
if (note.noteVisual != null)
{
note.noteVisual.isHighlighted = false;
try
{
note.noteVisual?.SetHighlight();
}
catch (Exception ex)
{
Debug.LogError($"Error setting highlight for note {note.name}: {ex.Message}");
}
}
2025-06-14 20:47:45 +08:00
}
}
// 按时间分组
var groups = SameTheme
? noteBases.GroupBy(n => (object)new { n.exactJudgeTime, Type = n.GetType() })
: noteBases.GroupBy(n => (object)n.exactJudgeTime);
foreach (var group in groups)
{
if (group.Count() > 1)
{
foreach (var note in group)
{
if (note.noteVisual != null)
{
note.noteVisual.isHighlighted = true;
try
{
note.noteVisual?.SetHighlight();
}
catch (Exception ex)
{
Debug.LogError($"Error setting highlight for note {note.name}: {ex.Message}");
}
}
2025-06-14 20:47:45 +08:00
}
}
}
}
public static void swapDisplacement()
{
Displacement displacement = inspector.connectedGameElement as Displacement;
if (displacement == null)
{
LogWindow.Log("Please select a Displacement first!", Color.red);
return;
}
foreach (var anim in displacement.positionX.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
foreach (var anim in displacement.positionY.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
foreach (var anim in displacement.positionZ.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
}
public static void swapSwirl()
{
Swirl swirl = inspector.connectedGameElement as Swirl;
if (swirl == null)
{
LogWindow.Log("Please select a Swirl first!", Color.red);
return;
}
foreach (var anim in swirl.eulerAngleX.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
foreach (var anim in swirl.eulerAngleY.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
foreach (var anim in swirl.eulerAngleZ.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
}
public static void swapScale()
{
Scale scale = inspector.connectedGameElement as Scale;
if (scale == null)
{
LogWindow.Log("Please select a Scale first!", Color.red);
return;
}
foreach (var anim in scale.scaleX.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
foreach (var anim in scale.scaleY.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
foreach (var anim in scale.scaleZ.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
}
public static void AttachNoteInNearestTrail()
{
Track track = inspector.connectedGameElement as Track;
if (track == null)
{
LogWindow.Log("Please select a Track first!", Color.red);
return;
}
List<NoteBase> noteBases = track.childElementList.OfType<NoteBase>().ToList();
List<IHaveTrail> trails = track.GetAllGameElementsFromThis().OfType<IHaveTrail>().ToList();
if (trails.Count == 0)
{
LogWindow.Log("The Track has no Trail!", Color.red);
return;
}
foreach (var note in noteBases)
{
IHaveTrail nearestTrail = null;
Vector3 FinalPos = Vector3.positiveInfinity;
foreach (var trail in trails)
{
if (trail is IHaveTransformSubmodule haveTransform && trail is GameElement gameElement)
{
Vector3 pos = haveTransform.transformSubmodule.originalPosition;
GameElement gameElement1 = gameElement;
while (gameElement1 != track)
{
if (gameElement1 is not IHaveTransformSubmodule)
{
gameElement1 = gameElement1.parentElement;
continue;
}
List<Displacement> animationBases = gameElement1.childElementList.OfType<Displacement>().ToList();
foreach (var displacement in animationBases)
{
pos += displacement.getValue(note.exactJudgeTime);
}
gameElement1 = gameElement1.parentElement;
}
if (Vector3.Distance(pos, (note.noteVisual.submoduleList.First(i => i is TransformSubmodule) as TransformSubmodule).originalPosition) <=
Vector3.Distance(FinalPos, (note.noteVisual.submoduleList.First(i => i is TransformSubmodule) as TransformSubmodule).originalPosition))
{
nearestTrail = trail;
FinalPos = pos;
}
}
}
if (nearestTrail != null)
{
(note.noteVisual.submoduleList.First(i => i is TransformSubmodule) as TransformSubmodule).originalPosition = FinalPos;
note.Refresh();
(note.noteVisual.submoduleList.First(i => i is TransformSubmodule) as TransformSubmodule).Refresh();//捏妈妈滴为什么notevisual的TransformSubmodule不刷新
}
}
}
// 导出Track下所有Note为正则格式文本
public static void ExportNotesFromTrack()
{
if (inspector.connectedGameElement == null || inspector.connectedGameElement.GetType() != typeof(Track))
{
LogWindow.Log("Please select a Track first!");
return;
}
Track track = (Track)inspector.connectedGameElement;
var notes = track.childElementList.OfType<NoteBase>().OrderBy(n => n.exactJudgeTime).ToList();
List<string> lines = new List<string>();
foreach (var note in notes)
{
string type = note switch
{
Tap => "Tap",
Stay => "Stay",
Hold => "Hold",
Flick => "Flick",
_ => "Unknown"
};
string id = track.elementName;
float time = note.exactJudgeTime;
float x = 0f;
// 获取X值
if (note.noteVisual.submoduleList.FirstOrDefault(i => i is TransformSubmodule) is TransformSubmodule ts)
{
x = ts.originalPosition.x;
}
if (note is Hold hold)
{
float duration = hold.holdEndTime - hold.exactJudgeTime;
lines.Add($"({type}, {id}, {time:0.###}, {x:0.###}, {duration:0.###})");
}
else
{
lines.Add($"({type}, {id}, {time:0.###}, {x:0.###})");
}
}
string result = string.Join("\n", lines);
Debug.Log(result);
//LogWindow.Log(result, Color.green);
// 复制到剪贴板
GUIUtility.systemCopyBuffer = result;
LogWindow.Log("Colped Done!", Color.green);
}
public static void AdjustPathnodeZ(float OriginZpoint, float scale)
{
2025-10-18 15:58:55 +08:00
if (inspector.connectedGameElement == null)
{
2025-10-18 15:58:55 +08:00
LogWindow.Log($"please select a element (folder or track)", Color.red);
return;
}
if (inspector.connectedGameElement.GetType() != typeof(Track))
{
foreach (var i in inspector.connectedGameElement.childElementList.OfType<Track>())
{
inspector.connectedGameElement = i;
AdjustPathnodeZ(OriginZpoint, scale);
}
return;
}
Track track = (Track)inspector.connectedGameElement;
var pathnodes = track.trackPathSubmodule.pathNodeList;
foreach (var pathnode in pathnodes)
{
if (pathnode.childElementList.OfType<Displacement>().Count() > 0)
{
LogWindow.Log($"PathNode {pathnode.elementName} has Displacement, which may cause issues", Color.yellow);
}
float worldZ = pathnode.transform.position.z;
float deltaZ = worldZ - OriginZpoint;
float newZ = OriginZpoint + deltaZ * scale;
pathnode.transform.position = new Vector3(pathnode.transform.position.x, pathnode.transform.position.y, newZ);
pathnode.transformSubmodule.originalPosition = pathnode.transform.localPosition;
pathnode.transformSubmodule.Refresh();
pathnode.Refresh();
}
2025-10-18 15:58:55 +08:00
foreach (var i in track.childElementList.OfType<Track>())
{
inspector.connectedGameElement = i;
AdjustPathnodeZ(OriginZpoint, scale);
}
}
public static void FloorAnim()
{
if (inspector.connectedGameElement == null)
{
LogWindow.Log("Please select a Element first!");
return;
}
List<AnimationBase> elements = inspector.connectedGameElement.GetAllGameElementsFromThis().OfType<AnimationBase>().ToList();
// 预先缓存属性信息(如果在循环外部知道具体类型)
var propertiesToCheck = typeof(GameElement).GetProperties()
.Where(p => p.PropertyType == typeof(FlexibleFloat))
.ToArray();
foreach (var element in elements)
{
bool needsRefresh = false;
foreach (var prop in propertiesToCheck)
{
var ff = prop.GetValue(element) as FlexibleFloat;
if (ff?.animations?.Count > 0 && ff.animations[0] != null)
{
var firstAnimation = ff.animations[0];
if (firstAnimation.startTime > 0)
{
ff.animations.Insert(0, new AnimatedFloat(
0,
Math.Min(firstAnimation.startTime, 1),
firstAnimation.startValue,
firstAnimation.startValue,
AnimationCurveType.Linear
));
needsRefresh = true;
Debug.Log($"Added 0 keyframe to {element.elementName}'s {prop.Name}");
}
}
}
if (needsRefresh)
{
element.Refresh();
element.animatedObject?.Refresh(); // 使用空条件运算符
}
}
}
public static void SplitHoldToTrack(int PathnodesCount)
{
if (inspector.connectedGameElement == null || inspector.connectedGameElement.GetType() != typeof(Hold))
{
LogWindow.Log("Please select a Hold first!");
return;
}
Hold hold = (Hold)inspector.connectedGameElement;
Track parentTrack = hold.parentElement as Track;
if (parentTrack == null || parentTrack.trackTimeSubmodule is not TrackTimeSubmoduleMovable)
{
LogWindow.Log("Track Illegal (Only Movable)", Color.red);
return;
}
TrackTimeSubmoduleMovable trackTimeSubmoduleMovable = hold.track.trackTimeSubmodule as TrackTimeSubmoduleMovable;
if (PathnodesCount < 2)
{
LogWindow.Log("PathnodesCount must be greater than 1!", Color.red);
return;
}
float startTime = hold.exactJudgeTime;
float endTime = hold.holdEndTime;
float interval = 1f / (PathnodesCount - 1);
hold.UpdateNoteInMovableTrack();
Vector3 HoldStartPos = default;
Vector3 HoldEndPos = default;
if (hold.noteVisual is DTMNoteVisualHold dTMNoteVisualHold)
{
dTMNoteVisualHold.headPoint.SetPercent(trackTimeSubmoduleMovable.GetTrackPercent(hold.exactJudgeTime));
dTMNoteVisualHold.tailPoint.SetPercent(trackTimeSubmoduleMovable.GetTrackPercent(hold.holdEndTime));
HoldStartPos = dTMNoteVisualHold.headPoint.transform.position;
HoldEndPos = dTMNoteVisualHold.tailPoint.transform.position;
}
else
{
LogWindow.Log("The selected Hold's NoteVisual is not DTMNoteVisualHold!", Color.red);
return;
}
if (hold.track.trackPathSubmodule.pathNodeList.Count > 2)
{
LogWindow.Log("the Hold may not be split currently", Color.yellow);
return;
}
hold.UpdateNoteInMovableTrack();
Track NewTrack = Track.GenerateElement(hold.elementName + "_SplitTrack", Guid.NewGuid(), new List<string>(), true, parentTrack);
new TrackTimeSubmoduleMovable(NewTrack, startTime, endTime, 1, AnimationCurveType.Linear);
for (int i = 0; i < PathnodesCount; i++)
{
PathNode j = PathNode.GenerateElement("PathNode" + i.ToString(), Guid.NewGuid(), new List<string>(), true, NewTrack, true);
j.transform.position = Vector3.Lerp(HoldStartPos, HoldEndPos, i * interval);
j.transformSubmodule.originalPosition = j.transform.localPosition;
}
EditorManager.instance.operationManager.CopyPasteDeleteModule.CopyElement(hold);
EditorManager.instance.operationManager.CopyPasteDeleteModule.PasteElement(NewTrack);
EditorManager.instance.operationManager.CopyPasteDeleteModule.DeleteElement(hold);
Hold newHold = NewTrack.childElementList.OfType<Hold>().First();
newHold.noteVisual.transformSubmodule.originalPosition = Vector3.zero;
NewTrack.Refresh();
Observable.Timer(TimeSpan.FromSeconds(0.3f)).Subscribe(_ =>
{
2025-10-18 15:58:55 +08:00
NewTrack?.trackPathSubmodule.path.RebuildImmediate(true, true);
DTMNoteVisualHold dTMNoteVisualHold = newHold.noteVisual as DTMNoteVisualHold;
dTMNoteVisualHold.meshGenerator.Rebuild();
});
}
public static void SplitAllHoldToTrack(int PathnodesCount)
{
if (inspector.connectedGameElement == null || inspector.connectedGameElement.GetType() != typeof(Track))
{
LogWindow.Log("Please select a Track first!");
return;
}
Track track = (Track)inspector.connectedGameElement;
var holds = track.childElementList.OfType<Hold>().ToList();
if (track.trackPathSubmodule.pathNodeList.Count > 2)
{
LogWindow.Log("the Hold may not be split currently", Color.yellow);
return;
}
2025-10-18 15:58:55 +08:00
foreach (var hold in holds)
{
inspector.connectedGameElement = hold;
SplitHoldToTrack(PathnodesCount);
}
}
2025-10-18 15:58:55 +08:00
public static void Rebuild()
{
foreach (GameElement element in EditorManager.instance.beatmapContainer.gameElementList)
{
foreach (GameElement e in element.GetAllGameElementsFromThis())
{
e.Refresh();
}
foreach (Track track in element.GetAllGameElementsFromThis().OfType<Track>())
{
2025-10-18 15:58:55 +08:00
track?.trackPathSubmodule.path.RebuildImmediate(true, true);
}
}
2025-10-18 15:58:55 +08:00
#if UNITY_EDITOR
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
#endif
}
2025-11-30 15:13:57 +08:00
public static void AddTagMatcher(string name, string parameterName)
{
var tagManager = EditorManager.instance.projectInformation.tagManager;
IBaseElement element = inspector.connectedGameElement;
tagManager.AddTagMatcher(name, element.GetType(), parameterName);
}
public static void FindParameterName(float value)
{
var element = inspector.connectedGameElement;
foreach (var i in element.GetType().GetFields())
{
if (i.FieldType == typeof(float) && (float)i.GetValue(element) == value)//获取对应变量的值)
{
Debug.Log($"Found parameter: {i.Name}");
LogWindow.Log($"Found parameter: {i.Name}", Color.green);
}
}
}
public static void FindParameterName(Vector3 value)
{
var element = inspector.connectedGameElement;
foreach (var field in element.GetType().GetFields())
{
if (field.FieldType == typeof(Vector3))
{
Vector3 fieldValue = (Vector3)field.GetValue(element);
if (Vector3.Distance(fieldValue, value) < 0.001f) // 使用容差比较Vector3
{
Debug.Log($"Found Vector3 parameter: {field.Name}");
LogWindow.Log($"Found Vector3 parameter: {field.Name}", Color.green);
}
}
}
}
public static void FindParameterName(Vector2 value)
{
var element = inspector.connectedGameElement;
foreach (var field in element.GetType().GetFields())
{
if (field.FieldType == typeof(Vector2))
{
Vector2 fieldValue = (Vector2)field.GetValue(element);
if (Vector2.Distance(fieldValue, value) < 0.001f) // 使用容差比较Vector2
{
Debug.Log($"Found Vector2 parameter: {field.Name}");
LogWindow.Log($"Found Vector2 parameter: {field.Name}", Color.green);
}
}
}
}
public static void FindParameterName(Color value)
{
var element = inspector.connectedGameElement;
foreach (var field in element.GetType().GetFields())
{
if (field.FieldType == typeof(Color))
{
Color fieldValue = (Color)field.GetValue(element);
if (fieldValue == value) // Color可以直接比较
{
Debug.Log($"Found Color parameter: {field.Name}");
LogWindow.Log($"Found Color parameter: {field.Name}", Color.green);
}
}
}
}
public static void FindParameterName(int value)
{
var element = inspector.connectedGameElement;
foreach (var field in element.GetType().GetFields())
{
if (field.FieldType == typeof(int))
{
int fieldValue = (int)field.GetValue(element);
if (fieldValue == value) // int可以直接比较
{
Debug.Log($"Found int parameter: {field.Name}");
LogWindow.Log($"Found int parameter: {field.Name}", Color.green);
}
}
}
}
public static void FindParameterName(string value)
{
var element = inspector.connectedGameElement;
foreach (var field in element.GetType().GetFields())
{
if (field.FieldType == typeof(string))
{
string fieldValue = (string)field.GetValue(element);
if (fieldValue == value) // string可以直接比较
{
Debug.Log($"Found string parameter: {field.Name}");
LogWindow.Log($"Found string parameter: {field.Name}", Color.green);
}
}
}
}
public static void SyncTagedElement()
{
var q = inspector.connectedGameElement;
var tagManager = EditorManager.instance.projectInformation.tagManager;
tagManager.SyncTagedElement((q));
}
2025-06-09 12:42:23 +08:00
}
}