using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using Ichni.RhythmGame; using Ichni.RhythmGame.Beatmap; using Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse; using UniRx; 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) { 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; } Track track = (Track)inspector.connectedGameElement; List oldNodes = track.trackPathSubmodule.pathNodeList.ToList(); List newNodes = new List(); // 如果 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); } } for (int i = 0; i < loop; i++) { float t = (float)i / (loop - 1); // 修正插值 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(), true, track, true); j.transformSubmodule.originalPosition = new Vector3(x, y, z); newNodes.Add(j); } } /// /// 将原有 PathNode 的变换(位置、旋转、缩放)迁移到新生成的最近 PathNode 上 /// public static bool AdjustPathNodesToNearest(Track track, List newNodes, List 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; } } return true; } // 支持主轴方向的螺旋线式 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(), 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(), 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 tracks = EditorManager.instance.beatmapContainer.gameElementList.OfType().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(), true, findTrack(id), timestamp); ((TransformSubmodule)a.noteVisual.submoduleList.Where(i => i is TransformSubmodule)?.First()).originalPosition = new Vector3(value, 0, 0); a.noteVisual.SetEditorSubmodules(); // 设置selset a.Refresh(); break; case "Stay": Stay b = Stay.GenerateElement("New Stay", Guid.NewGuid(), new List(), true, findTrack(id), timestamp); ((TransformSubmodule)b.noteVisual.submoduleList.Where(i => i is TransformSubmodule)?.First()).originalPosition = new Vector3(value, 0, 0); b.noteVisual.SetEditorSubmodules(); // 设置selset b.Refresh(); break; case "Hold": Hold c = Hold.GenerateElement("New Hold", Guid.NewGuid(), new List(), true, findTrack(id), timestamp, timestamp + holdDuration); ((TransformSubmodule)c.noteVisual.submoduleList.Where(i => i is TransformSubmodule)?.First()).originalPosition = new Vector3(value, 0, 0); c.noteVisual.SetEditorSubmodules(); // 设置selset c.Refresh(); break; case "Flick": Flick d = Flick.GenerateElement("New Flick", Guid.NewGuid(), new List(), true, findTrack(id), timestamp, new List()); ((TransformSubmodule)d.noteVisual.submoduleList.Where(i => i is TransformSubmodule)?.First()).originalPosition = new Vector3(value, 0, 0); d.noteVisual.SetEditorSubmodules(); // 设置selset d.Refresh(); break; default: Debug.LogError($"未知类型: {action}"); break; } } } Debug.Log("===== ====="); } public static void SetNoteHLInGame(bool forceSetOff = false, bool SameTheme = false) { var noteBases = EditorManager.instance.beatmapContainer.gameElementList.OfType().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}"); } } } } // 按时间分组 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}"); } } } } } } public static void SetNoteHLInElement(bool forceSetOff = false, bool SameTheme = false) { var noteBases = inspector.connectedGameElement.GetAllGameElementsFromThis().OfType().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}"); } } } } // 按时间分组 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}"); } } } } } } 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 noteBases = track.childElementList.OfType().ToList(); List trails = track.GetAllGameElementsFromThis().OfType().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 animationBases = gameElement1.childElementList.OfType().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().OrderBy(n => n.exactJudgeTime).ToList(); List lines = new List(); 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) { if (inspector.connectedGameElement == null) { 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()) { 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().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(); } foreach (var i in track.childElementList.OfType()) { inspector.connectedGameElement = i; AdjustPathnodeZ(OriginZpoint, scale); } } public static void FloorAnim() { if (inspector.connectedGameElement == null) { LogWindow.Log("Please select a Element first!"); return; } List elements = inspector.connectedGameElement.GetAllGameElementsFromThis().OfType().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(), 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(), 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().First(); newHold.noteVisual.transformSubmodule.originalPosition = Vector3.zero; NewTrack.Refresh(); Observable.Timer(TimeSpan.FromSeconds(0.3f)).Subscribe(_ => { 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().ToList(); if (track.trackPathSubmodule.pathNodeList.Count > 2) { LogWindow.Log("the Hold may not be split currently", Color.yellow); return; } foreach (var hold in holds) { inspector.connectedGameElement = hold; SplitHoldToTrack(PathnodesCount); } } 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?.trackPathSubmodule.path.RebuildImmediate(true, true); } } #if UNITY_EDITOR UnityEditorInternal.InternalEditorUtility.RepaintAllViews(); #endif } 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)); } } }