我死去
目前添加了一个能够深度查找和设置反射的helper,但是Tag的系统仍然不完全,另外我觉得console可以重构了 Signed-off-by: TRAfoer <lhf190@outlook.com>
This commit is contained in:
32885
Assets/FR2_Cache.asset
32885
Assets/FR2_Cache.asset
File diff suppressed because it is too large
Load Diff
@@ -46,33 +46,14 @@ MonoBehaviour:
|
|||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
serializationData:
|
serializationData:
|
||||||
SerializedFormat: 2
|
SerializedFormat: 0
|
||||||
SerializedBytes:
|
SerializedBytes: 29010b00000065006c0065006d0065006e007400470075006900640037792c70b476d344ad481072561faaec01010d0000007300750062006d006f00640075006c0065004c006900730074002f00000000015e000000530079007300740065006d002e0043006f006c006c0065006300740069006f006e0073002e00470065006e0065007200690063002e004c00690073007400600031005b005b004900630068006e0069002e00520068007900740068006d00470061006d0065002e005300750062006d006f00640075006c00650042006100730065002c00200041007300730065006d0062006c0079002d004300530068006100720070005d005d002c0020006d00730063006f0072006c00690062000000000006000000000000000007052d010b00000065006e00610062006c00650054007900700065007300
|
||||||
ReferencedUnityObjects: []
|
ReferencedUnityObjects: []
|
||||||
SerializedBytesString:
|
SerializedBytesString:
|
||||||
Prefab: {fileID: 0}
|
Prefab: {fileID: 0}
|
||||||
PrefabModificationsReferencedUnityObjects: []
|
PrefabModificationsReferencedUnityObjects: []
|
||||||
PrefabModifications: []
|
PrefabModifications: []
|
||||||
SerializationNodes:
|
SerializationNodes: []
|
||||||
- Name: elementGuid
|
|
||||||
Entry: 2
|
|
||||||
Data: 702c793776b444d3ad481072561faaec
|
|
||||||
- Name: submoduleList
|
|
||||||
Entry: 7
|
|
||||||
Data: 0|System.Collections.Generic.List`1[[Ichni.RhythmGame.SubmoduleBase,
|
|
||||||
Assembly-CSharp]], mscorlib
|
|
||||||
- Name:
|
|
||||||
Entry: 12
|
|
||||||
Data: 0
|
|
||||||
- Name:
|
|
||||||
Entry: 13
|
|
||||||
Data:
|
|
||||||
- Name:
|
|
||||||
Entry: 8
|
|
||||||
Data:
|
|
||||||
- Name: enableTypes
|
|
||||||
Entry: 6
|
|
||||||
Data:
|
|
||||||
elementName:
|
elementName:
|
||||||
tags: []
|
tags: []
|
||||||
parentElement: {fileID: 0}
|
parentElement: {fileID: 0}
|
||||||
@@ -249,7 +230,7 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3}
|
m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
m_RenderShadows: 1
|
m_RenderShadows: 0
|
||||||
m_RequiresDepthTextureOption: 2
|
m_RequiresDepthTextureOption: 2
|
||||||
m_RequiresOpaqueTextureOption: 2
|
m_RequiresOpaqueTextureOption: 2
|
||||||
m_CameraType: 0
|
m_CameraType: 0
|
||||||
@@ -261,7 +242,7 @@ MonoBehaviour:
|
|||||||
m_VolumeTrigger: {fileID: 0}
|
m_VolumeTrigger: {fileID: 0}
|
||||||
m_VolumeFrameworkUpdateModeOption: 2
|
m_VolumeFrameworkUpdateModeOption: 2
|
||||||
m_RenderPostProcessing: 1
|
m_RenderPostProcessing: 1
|
||||||
m_Antialiasing: 0
|
m_Antialiasing: 2
|
||||||
m_AntialiasingQuality: 2
|
m_AntialiasingQuality: 2
|
||||||
m_StopNaN: 0
|
m_StopNaN: 0
|
||||||
m_Dithering: 0
|
m_Dithering: 0
|
||||||
|
|||||||
@@ -8,21 +8,22 @@ Material:
|
|||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_Name: TrackDisplayer
|
m_Name: TrackDisplayer
|
||||||
m_Shader: {fileID: 4800000, guid: 8516d7a69675844a7a0b7095af7c46af, type: 3}
|
m_Shader: {fileID: 4800000, guid: 650dd9526735d5b46b79224bc6e94025, type: 3}
|
||||||
m_Parent: {fileID: 0}
|
m_Parent: {fileID: 0}
|
||||||
m_ModifiedSerializedProperties: 0
|
m_ModifiedSerializedProperties: 0
|
||||||
m_ValidKeywords:
|
m_ValidKeywords:
|
||||||
- _EMISSION
|
- _SURFACE_TYPE_TRANSPARENT
|
||||||
- _RECEIVE_SHADOWS_OFF
|
|
||||||
m_InvalidKeywords:
|
m_InvalidKeywords:
|
||||||
- _FLIPBOOKBLENDING_OFF
|
- _EMISSION
|
||||||
m_LightmapFlags: 0
|
m_LightmapFlags: 0
|
||||||
m_EnableInstancingVariants: 0
|
m_EnableInstancingVariants: 0
|
||||||
m_DoubleSidedGI: 1
|
m_DoubleSidedGI: 0
|
||||||
m_CustomRenderQueue: 2010
|
m_CustomRenderQueue: 3010
|
||||||
stringTagMap:
|
stringTagMap:
|
||||||
RenderType: Opaque
|
RenderType: Transparent
|
||||||
disabledShaderPasses: []
|
disabledShaderPasses:
|
||||||
|
- DepthOnly
|
||||||
|
- SHADOWCASTER
|
||||||
m_LockedProperties:
|
m_LockedProperties:
|
||||||
m_SavedProperties:
|
m_SavedProperties:
|
||||||
serializedVersion: 3
|
serializedVersion: 3
|
||||||
@@ -109,7 +110,7 @@ Material:
|
|||||||
- _ClearCoatMask: 0
|
- _ClearCoatMask: 0
|
||||||
- _ClearCoatSmoothness: 0
|
- _ClearCoatSmoothness: 0
|
||||||
- _ColorMode: 0
|
- _ColorMode: 0
|
||||||
- _Cull: 0
|
- _Cull: 2
|
||||||
- _Cutoff: 0.5
|
- _Cutoff: 0.5
|
||||||
- _DetailAlbedoMapScale: 1
|
- _DetailAlbedoMapScale: 1
|
||||||
- _DetailNormalMapScale: 1
|
- _DetailNormalMapScale: 1
|
||||||
@@ -117,8 +118,8 @@ Material:
|
|||||||
- _DistortionEnabled: 0
|
- _DistortionEnabled: 0
|
||||||
- _DistortionStrength: 1
|
- _DistortionStrength: 1
|
||||||
- _DistortionStrengthScaled: 0.1
|
- _DistortionStrengthScaled: 0.1
|
||||||
- _DstBlend: 0
|
- _DstBlend: 10
|
||||||
- _DstBlendAlpha: 0
|
- _DstBlendAlpha: 10
|
||||||
- _EmissionEnabled: 0
|
- _EmissionEnabled: 0
|
||||||
- _EnableExternalAlpha: 0
|
- _EnableExternalAlpha: 0
|
||||||
- _EnvironmentReflections: 1
|
- _EnvironmentReflections: 1
|
||||||
@@ -136,6 +137,7 @@ Material:
|
|||||||
- _QueueControl: 0
|
- _QueueControl: 0
|
||||||
- _QueueOffset: 10
|
- _QueueOffset: 10
|
||||||
- _ReceiveShadows: 0
|
- _ReceiveShadows: 0
|
||||||
|
- _SampleGI: 0
|
||||||
- _Shininess: 0
|
- _Shininess: 0
|
||||||
- _Smoothness: 0
|
- _Smoothness: 0
|
||||||
- _SmoothnessSource: 0
|
- _SmoothnessSource: 0
|
||||||
@@ -145,9 +147,9 @@ Material:
|
|||||||
- _SoftParticlesNearFadeDistance: 0
|
- _SoftParticlesNearFadeDistance: 0
|
||||||
- _SpecSource: 0
|
- _SpecSource: 0
|
||||||
- _SpecularHighlights: 1
|
- _SpecularHighlights: 1
|
||||||
- _SrcBlend: 1
|
- _SrcBlend: 5
|
||||||
- _SrcBlendAlpha: 1
|
- _SrcBlendAlpha: 1
|
||||||
- _Surface: 0
|
- _Surface: 1
|
||||||
- _UseAoMap: 0
|
- _UseAoMap: 0
|
||||||
- _UseColorMap: 0
|
- _UseColorMap: 0
|
||||||
- _UseEmissiveMap: 0
|
- _UseEmissiveMap: 0
|
||||||
@@ -155,7 +157,7 @@ Material:
|
|||||||
- _UseNormalMap: 0
|
- _UseNormalMap: 0
|
||||||
- _UseRoughnessMap: 0
|
- _UseRoughnessMap: 0
|
||||||
- _WorkflowMode: 1
|
- _WorkflowMode: 1
|
||||||
- _ZWrite: 1
|
- _ZWrite: 0
|
||||||
m_Colors:
|
m_Colors:
|
||||||
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
|
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
|
||||||
- _BaseColorAddSubDiff: {r: 0, g: 0, b: 0, a: 0}
|
- _BaseColorAddSubDiff: {r: 0, g: 0, b: 0, a: 0}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -46,6 +46,8 @@ namespace Ichni.Editor
|
|||||||
));
|
));
|
||||||
return $"{methodName} {paramHint}".Trim() + "\n";
|
return $"{methodName} {paramHint}".Trim() + "\n";
|
||||||
}
|
}
|
||||||
|
// ... (omitted parts)
|
||||||
|
|
||||||
public void GetChange(string change)
|
public void GetChange(string change)
|
||||||
{
|
{
|
||||||
if (change == "help")
|
if (change == "help")
|
||||||
@@ -80,8 +82,9 @@ namespace Ichni.Editor
|
|||||||
string funcName = match.Groups[1].Value;
|
string funcName = match.Groups[1].Value;
|
||||||
|
|
||||||
// 2. 查找方法
|
// 2. 查找方法
|
||||||
|
// 【修改点】:使用 StringComparison.OrdinalIgnoreCase 实现忽略大小写的查找
|
||||||
List<MethodInfo> methods = typeof(EditorConsoleMethods).GetMethods()
|
List<MethodInfo> methods = typeof(EditorConsoleMethods).GetMethods()
|
||||||
.Where(m => m.IsStatic && m.IsPublic && m.ReturnType == typeof(void) && m.Name.Contains(funcName)).ToList();
|
.Where(m => m.IsStatic && m.IsPublic && m.ReturnType == typeof(void) && m.Name.IndexOf(funcName, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
|
||||||
cueText.text = "";
|
cueText.text = "";
|
||||||
for (int i = 0; i < methods.Count; i++)
|
for (int i = 0; i < methods.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -96,6 +99,7 @@ namespace Ichni.Editor
|
|||||||
|
|
||||||
// t.RunSynchronously();
|
// t.RunSynchronously();
|
||||||
}
|
}
|
||||||
|
// ... (omitted parts)
|
||||||
public void GetCommand(string Command)//当提交命令时
|
public void GetCommand(string Command)//当提交命令时
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -132,7 +136,42 @@ namespace Ichni.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// 在 TransformCommand 或 CheckCtrlNumberShortcut 附近添加
|
||||||
|
|
||||||
|
// 辅助方法:获取 cueText 中第一个提示的命令名
|
||||||
|
private string GetFinalCommandForExecution(string input)
|
||||||
|
{
|
||||||
|
string trimmed = input.Trim();
|
||||||
|
|
||||||
|
// 1. 提取用户输入的命令名部分
|
||||||
|
var match = Regex.Match(trimmed, @"^(\w+)");
|
||||||
|
if (!match.Success)
|
||||||
|
{
|
||||||
|
// 如果不是合法的命令开头,直接尝试转换并返回 (DynamicExpresso 也许能处理赋值)
|
||||||
|
return TransformCommand(trimmed);
|
||||||
|
}
|
||||||
|
string funcName = match.Groups[1].Value;
|
||||||
|
|
||||||
|
// 2. 重新查找匹配的方法 (和 GetChange 逻辑一致,保证一致性)
|
||||||
|
List<MethodInfo> methods = typeof(EditorConsoleMethods).GetMethods()
|
||||||
|
.Where(m => m.IsStatic && m.IsPublic && m.ReturnType == typeof(void) && m.Name.IndexOf(funcName, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
|
||||||
|
|
||||||
|
string finalCommandToTransform = input;
|
||||||
|
|
||||||
|
// 3. 找到最佳匹配并替换
|
||||||
|
if (methods.Count > 0)
|
||||||
|
{
|
||||||
|
// 最佳匹配是列表中的第一个方法名
|
||||||
|
string firstCommand = methods[0].Name;
|
||||||
|
|
||||||
|
// 替换用户输入中的命令名部分为完整的、匹配到的命令名
|
||||||
|
// 例如:用户输入 "pr 10",替换为 "print 10"
|
||||||
|
finalCommandToTransform = Regex.Replace(trimmed, @"^(\w+)", firstCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 转换并返回 DynamicExpresso 表达式
|
||||||
|
return TransformCommand(finalCommandToTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//这是史,不要看
|
//这是史,不要看
|
||||||
@@ -165,19 +204,20 @@ namespace Ichni.Editor
|
|||||||
// 提交命令
|
// 提交命令
|
||||||
if (Keyboard.current.enterKey.wasPressedThisFrame)
|
if (Keyboard.current.enterKey.wasPressedThisFrame)
|
||||||
{
|
{
|
||||||
string input = InputCommand.text;
|
string input = InputCommand.text; // 原始命令文本
|
||||||
if (string.IsNullOrWhiteSpace(input))
|
if (string.IsNullOrWhiteSpace(input))
|
||||||
{
|
{
|
||||||
InputCommand.text = "";
|
InputCommand.text = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
string ExpoCommand = TransformCommand(input);
|
|
||||||
|
|
||||||
|
// 【修改点】:调用新方法获取最终执行的命令(已包含修正逻辑和 TransformCommand)
|
||||||
|
string ExpoCommand = GetFinalCommandForExecution(input);
|
||||||
|
|
||||||
print(ExpoCommand);
|
// print(ExpoCommand); // 调试语句,可选
|
||||||
GetCommand(ExpoCommand);
|
GetCommand(ExpoCommand);
|
||||||
|
|
||||||
// 记录历史命令
|
// 记录历史命令,使用原始命令 input
|
||||||
if (historyCommand.ContainsKey(historycount))
|
if (historyCommand.ContainsKey(historycount))
|
||||||
historyCommand[historycount] = input;
|
historyCommand[historycount] = input;
|
||||||
else
|
else
|
||||||
@@ -306,6 +346,7 @@ namespace Ichni.Editor
|
|||||||
{
|
{
|
||||||
functionInterpreter = new Interpreter()
|
functionInterpreter = new Interpreter()
|
||||||
.Reference(typeof(Vector3))
|
.Reference(typeof(Vector3))
|
||||||
|
.Reference(typeof(Color))
|
||||||
.Reference(typeof(Vector2));//这是AI给的东西?
|
.Reference(typeof(Vector2));//这是AI给的东西?
|
||||||
foreach (MethodInfo i in typeof(EditorConsoleMethods).GetMethods().
|
foreach (MethodInfo i in typeof(EditorConsoleMethods).GetMethods().
|
||||||
ToList().Where(i => i.IsStatic && i.IsPublic && (i.ReturnType == typeof(void))))
|
ToList().Where(i => i.IsStatic && i.IsPublic && (i.ReturnType == typeof(void))))
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Ichni.RhythmGame;
|
using Ichni.RhythmGame;
|
||||||
@@ -15,11 +16,16 @@ namespace Ichni.Editor
|
|||||||
{
|
{
|
||||||
public static class EditorConsoleMethods
|
public static class EditorConsoleMethods
|
||||||
{
|
{
|
||||||
|
#region UI/Manager Accessors (UI/管理器访问器)
|
||||||
public static Inspector inspector => EditorManager.instance.uiManager.inspector;
|
public static Inspector inspector => EditorManager.instance.uiManager.inspector;
|
||||||
public static Hierarchy hierarchy => EditorManager.instance.uiManager.hierarchy;
|
public static Hierarchy hierarchy => EditorManager.instance.uiManager.hierarchy;
|
||||||
public static LogWindow logWindow => EditorManager.instance.uiManager.mainPage.logWindow;
|
public static LogWindow logWindow => EditorManager.instance.uiManager.mainPage.logWindow;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Scene/Transform Operations (场景/变换操作)
|
||||||
|
/// <summary>
|
||||||
|
/// 传送场景相机到指定位置
|
||||||
|
/// </summary>
|
||||||
public static void tp(Vector3 pos)
|
public static void tp(Vector3 pos)
|
||||||
{
|
{
|
||||||
if (EditorManager.instance.cameraManager.isSceneCameraActive)
|
if (EditorManager.instance.cameraManager.isSceneCameraActive)
|
||||||
@@ -27,7 +33,10 @@ namespace Ichni.Editor
|
|||||||
EditorManager.instance.cameraManager.sceneCamera.sceneCamera.transform.position = pos;
|
EditorManager.instance.cameraManager.sceneCamera.sceneCamera.transform.position = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 保留无参tp
|
|
||||||
|
/// <summary>
|
||||||
|
/// 传送场景相机到选中元素位置
|
||||||
|
/// </summary>
|
||||||
public static void tp()
|
public static void tp()
|
||||||
{
|
{
|
||||||
if (EditorManager.instance.cameraManager.isSceneCameraActive)
|
if (EditorManager.instance.cameraManager.isSceneCameraActive)
|
||||||
@@ -37,13 +46,20 @@ namespace Ichni.Editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重命名选中元素
|
||||||
|
/// </summary>
|
||||||
public static void ReName(string message)
|
public static void ReName(string message)
|
||||||
{
|
{
|
||||||
inspector.connectedGameElement.elementName = message;
|
inspector.connectedGameElement.elementName = message;
|
||||||
inspector.connectedGameElement.Refresh();
|
inspector.connectedGameElement.Refresh();
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region PathNode Generation (路径节点生成)
|
||||||
|
/// <summary>
|
||||||
|
/// 直线路径节点生成 (Line PathNode Generator)
|
||||||
|
/// </summary>
|
||||||
public static void Lgp(int loop, Vector3 start, Vector3 end, bool Clear = false, bool offsetOrigin = false)
|
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))
|
if (inspector.connectedGameElement == null || inspector.connectedGameElement.GetType() != typeof(Track))
|
||||||
@@ -88,35 +104,8 @@ namespace Ichni.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将原有 PathNode 的变换(位置、旋转、缩放)迁移到新生成的最近 PathNode 上
|
/// 主轴方向的螺旋线式 PathNode
|
||||||
/// </summary>
|
/// </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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 支持主轴方向的螺旋线式 PathNode
|
|
||||||
public static void Spiral(int loop, Vector3 center, float r, float h, int pointsPerTurn, string axis = "y")
|
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))
|
if (inspector.connectedGameElement == null || inspector.connectedGameElement.GetType() != typeof(Track))
|
||||||
@@ -160,7 +149,9 @@ namespace Ichni.Editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 任意方向的螺旋线式 PathNode(中心点和方向均为Vector3)
|
/// <summary>
|
||||||
|
/// 任意方向的螺旋线式 PathNode(中心点和方向均为Vector3)
|
||||||
|
/// </summary>
|
||||||
public static void Spiral(int loop, Vector3 center, float r, float h, int pointsPerTurn, Vector3 dir)
|
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))
|
if (inspector.connectedGameElement == null || inspector.connectedGameElement.GetType() != typeof(Track))
|
||||||
@@ -189,6 +180,41 @@ namespace Ichni.Editor
|
|||||||
node.transformSubmodule.originalPosition = pos;
|
node.transformSubmodule.originalPosition = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region PathNode/Track Utilities (路径节点/轨道工具)
|
||||||
|
|
||||||
|
/// <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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除父元素下所有与当前选中元素类型相同的其他元素,最后删除当前选中元素
|
||||||
|
/// </summary>
|
||||||
public static void DelSameInParent()
|
public static void DelSameInParent()
|
||||||
{
|
{
|
||||||
Type type = inspector.connectedGameElement.GetType();
|
Type type = inspector.connectedGameElement.GetType();
|
||||||
@@ -206,6 +232,213 @@ namespace Ichni.Editor
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将选中轨道下所有音符附着到最近的 Trail 上
|
||||||
|
/// </summary>
|
||||||
|
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不刷新
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 调整路径节点的 Z 坐标(可用于多轨道)
|
||||||
|
/// </summary>
|
||||||
|
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<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();
|
||||||
|
}
|
||||||
|
foreach (var i in track.childElementList.OfType<Track>())
|
||||||
|
{
|
||||||
|
inspector.connectedGameElement = i;
|
||||||
|
AdjustPathnodeZ(OriginZpoint, scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将 Hold Note 拆分为具有路径节点的 Track
|
||||||
|
/// </summary>
|
||||||
|
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(_ =>
|
||||||
|
{
|
||||||
|
NewTrack?.trackPathSubmodule.path.RebuildImmediate(true, true);
|
||||||
|
DTMNoteVisualHold dTMNoteVisualHold = newHold.noteVisual as DTMNoteVisualHold;
|
||||||
|
dTMNoteVisualHold.meshGenerator.Rebuild();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将选中轨道下所有 Hold Note 拆分为具有路径节点的 Track
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var hold in holds)
|
||||||
|
{
|
||||||
|
inspector.connectedGameElement = hold;
|
||||||
|
SplitHoldToTrack(PathnodesCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Note Import/Export (音符导入/导出)
|
||||||
|
/// <summary>
|
||||||
|
/// 从正则格式文本导入音符数据
|
||||||
|
/// </summary>
|
||||||
public static void SamplerImport(string inputData)
|
public static void SamplerImport(string inputData)
|
||||||
{
|
{
|
||||||
if (!EditorManager.instance.useNotePrefab)
|
if (!EditorManager.instance.useNotePrefab)
|
||||||
@@ -316,6 +549,61 @@ namespace Ichni.Editor
|
|||||||
}
|
}
|
||||||
Debug.Log("===== =====");
|
Debug.Log("===== =====");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 导出选中轨道下所有音符为正则格式文本(复制到剪贴板)
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Highlighting/Visuals (高亮/视觉效果)
|
||||||
|
/// <summary>
|
||||||
|
/// 在游戏内设置时间相同的音符高亮显示
|
||||||
|
/// </summary>
|
||||||
public static void SetNoteHLInGame(bool forceSetOff = false, bool SameTheme = false)
|
public static void SetNoteHLInGame(bool forceSetOff = false, bool SameTheme = false)
|
||||||
{
|
{
|
||||||
var noteBases = EditorManager.instance.beatmapContainer.gameElementList.OfType<NoteBase>().ToList();
|
var noteBases = EditorManager.instance.beatmapContainer.gameElementList.OfType<NoteBase>().ToList();
|
||||||
@@ -369,6 +657,9 @@ namespace Ichni.Editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在选中元素下设置时间相同的音符高亮显示
|
||||||
|
/// </summary>
|
||||||
public static void SetNoteHLInElement(bool forceSetOff = false, bool SameTheme = false)
|
public static void SetNoteHLInElement(bool forceSetOff = false, bool SameTheme = false)
|
||||||
{
|
{
|
||||||
var noteBases = inspector.connectedGameElement.GetAllGameElementsFromThis().OfType<NoteBase>().ToList();
|
var noteBases = inspector.connectedGameElement.GetAllGameElementsFromThis().OfType<NoteBase>().ToList();
|
||||||
@@ -422,6 +713,12 @@ namespace Ichni.Editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Animation Swaps (动画值交换)
|
||||||
|
/// <summary>
|
||||||
|
/// 交换 Displacement 动画值的正负号
|
||||||
|
/// </summary>
|
||||||
public static void swapDisplacement()
|
public static void swapDisplacement()
|
||||||
{
|
{
|
||||||
Displacement displacement = inspector.connectedGameElement as Displacement;
|
Displacement displacement = inspector.connectedGameElement as Displacement;
|
||||||
@@ -446,6 +743,10 @@ namespace Ichni.Editor
|
|||||||
anim.startValue = -anim.startValue;
|
anim.startValue = -anim.startValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 交换 Swirl 动画值的正负号
|
||||||
|
/// </summary>
|
||||||
public static void swapSwirl()
|
public static void swapSwirl()
|
||||||
{
|
{
|
||||||
Swirl swirl = inspector.connectedGameElement as Swirl;
|
Swirl swirl = inspector.connectedGameElement as Swirl;
|
||||||
@@ -470,6 +771,10 @@ namespace Ichni.Editor
|
|||||||
anim.startValue = -anim.startValue;
|
anim.startValue = -anim.startValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 交换 Scale 动画值的正负号
|
||||||
|
/// </summary>
|
||||||
public static void swapScale()
|
public static void swapScale()
|
||||||
{
|
{
|
||||||
Scale scale = inspector.connectedGameElement as Scale;
|
Scale scale = inspector.connectedGameElement as Scale;
|
||||||
@@ -494,147 +799,12 @@ namespace Ichni.Editor
|
|||||||
anim.startValue = -anim.startValue;
|
anim.startValue = -anim.startValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void AttachNoteInNearestTrail()
|
#endregion
|
||||||
{
|
|
||||||
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)
|
#region Global Utilities (全局工具)
|
||||||
{
|
/// <summary>
|
||||||
pos += displacement.getValue(note.exactJudgeTime);
|
/// 确保所有动画的起始时间为 0 时有关键帧
|
||||||
}
|
/// </summary>
|
||||||
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)
|
|
||||||
{
|
|
||||||
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<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();
|
|
||||||
}
|
|
||||||
foreach (var i in track.childElementList.OfType<Track>())
|
|
||||||
{
|
|
||||||
inspector.connectedGameElement = i;
|
|
||||||
AdjustPathnodeZ(OriginZpoint, scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static void FloorAnim()
|
public static void FloorAnim()
|
||||||
{
|
{
|
||||||
if (inspector.connectedGameElement == null)
|
if (inspector.connectedGameElement == null)
|
||||||
@@ -681,97 +851,10 @@ namespace Ichni.Editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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(_ =>
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var hold in holds)
|
|
||||||
{
|
|
||||||
inspector.connectedGameElement = hold;
|
|
||||||
SplitHoldToTrack(PathnodesCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 全局刷新所有元素和轨道路径
|
||||||
|
/// </summary>
|
||||||
public static void Rebuild()
|
public static void Rebuild()
|
||||||
{
|
{
|
||||||
foreach (GameElement element in EditorManager.instance.beatmapContainer.gameElementList)
|
foreach (GameElement element in EditorManager.instance.beatmapContainer.gameElementList)
|
||||||
@@ -789,6 +872,10 @@ namespace Ichni.Editor
|
|||||||
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
|
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加 Tag Matcher 到 TagManager
|
||||||
|
/// </summary>
|
||||||
public static void AddTagMatcher(string name, string parameterName)
|
public static void AddTagMatcher(string name, string parameterName)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -796,102 +883,67 @@ namespace Ichni.Editor
|
|||||||
IBaseElement element = inspector.connectedGameElement;
|
IBaseElement element = inspector.connectedGameElement;
|
||||||
tagManager.AddTagMatcher(name, element.GetType(), parameterName);
|
tagManager.AddTagMatcher(name, element.GetType(), parameterName);
|
||||||
}
|
}
|
||||||
public static void FindParameterName(float value)
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找元素中匹配给定值的参数名称
|
||||||
|
/// </summary>
|
||||||
|
public static void FindParameterName(object value)
|
||||||
{
|
{
|
||||||
|
// 假设 inspector.connectedGameElement 存在且是你希望搜索的对象
|
||||||
var element = inspector.connectedGameElement;
|
var element = inspector.connectedGameElement;
|
||||||
foreach (var i in element.GetType().GetFields())
|
if (element == null || value == null) return;
|
||||||
|
string o = FindParameterName(element, value);
|
||||||
|
if (!string.IsNullOrEmpty(o)) LogWindow.Log(o);
|
||||||
|
|
||||||
|
foreach (var i in element.GetType().GetProperties(DeepMatchFlags))
|
||||||
{
|
{
|
||||||
if (i.FieldType == typeof(float) && (float)i.GetValue(element) == value)//获取对应变量的值)
|
if (i == null) continue;
|
||||||
{
|
var propertyInfo = element.GetType().GetProperty(i.Name);
|
||||||
Debug.Log($"Found parameter: {i.Name}");
|
if (propertyInfo == null) continue;
|
||||||
LogWindow.Log($"Found parameter: {i.Name}", Color.green);
|
var propertyValue = propertyInfo.GetValue(element);
|
||||||
}
|
var p = FindParameterName(propertyValue as IBaseElement, value);
|
||||||
|
if (!string.IsNullOrEmpty(p))
|
||||||
|
LogWindow.Log($"{i.Name}.{p}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void FindParameterName(Vector3 value)
|
public static string FindParameterName(IBaseElement element, object value)
|
||||||
{
|
{
|
||||||
var element = inspector.connectedGameElement;
|
// 假设 inspector.connectedGameElement 存在且是你希望搜索的对象
|
||||||
foreach (var field in element.GetType().GetFields())
|
|
||||||
|
if (element == null || value == null) return "";
|
||||||
|
|
||||||
|
// 1. 获取目标类型
|
||||||
|
Type targetType = value.GetType();
|
||||||
|
|
||||||
|
// 如果是 Nullable<T>,获取其基础类型
|
||||||
|
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||||
{
|
{
|
||||||
if (field.FieldType == typeof(Vector3))
|
targetType = Nullable.GetUnderlyingType(targetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 遍历 GameElement 的所有字段
|
||||||
|
foreach (var field in element.GetType().GetFields(DeepMatchFlags))
|
||||||
|
{
|
||||||
|
// 检查字段类型是否匹配
|
||||||
|
if (field.FieldType == targetType)
|
||||||
{
|
{
|
||||||
Vector3 fieldValue = (Vector3)field.GetValue(element);
|
// 获取字段的值 (作为 object)
|
||||||
if (Vector3.Distance(fieldValue, value) < 0.001f) // 使用容差比较Vector3
|
object fieldValue = field.GetValue(element);
|
||||||
|
|
||||||
|
if (IsValueMatch(fieldValue, value, field.FieldType))
|
||||||
{
|
{
|
||||||
Debug.Log($"Found Vector3 parameter: {field.Name}");
|
Debug.Log($"Found parameter: {field.Name} (Type: {targetType.Name})");
|
||||||
LogWindow.Log($"Found Vector3 parameter: {field.Name}", Color.green);
|
// 假设 LogWindow 可用
|
||||||
|
return field.Name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void FindParameterName(Vector2 value)
|
/// <summary>
|
||||||
{
|
/// 同步标签元素
|
||||||
var element = inspector.connectedGameElement;
|
/// </summary>
|
||||||
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()
|
public static void SyncTagedElement()
|
||||||
{
|
{
|
||||||
var q = inspector.connectedGameElement;
|
var q = inspector.connectedGameElement;
|
||||||
@@ -899,5 +951,98 @@ namespace Ichni.Editor
|
|||||||
var tagManager = EditorManager.instance.projectInformation.tagManager;
|
var tagManager = EditorManager.instance.projectInformation.tagManager;
|
||||||
tagManager.SyncTagedElement((q));
|
tagManager.SyncTagedElement((q));
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Internal Helpers (内部辅助方法)
|
||||||
|
private const BindingFlags DeepMatchFlags = BindingFlags.Instance | BindingFlags.Public;
|
||||||
|
private const float FloatEpsilon = 0.0001f; // 定义浮点数容差
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 比较两个值是否匹配,对浮点数使用容差比较
|
||||||
|
/// </summary>
|
||||||
|
private static bool IsValueMatch(object fieldVal, object targetVal, Type t)
|
||||||
|
{
|
||||||
|
if (fieldVal == null || targetVal == null)
|
||||||
|
{
|
||||||
|
return fieldVal == targetVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 类型是 float
|
||||||
|
if (t == typeof(float))
|
||||||
|
{
|
||||||
|
// 必须进行类型转换
|
||||||
|
float f1 = (float)fieldVal;
|
||||||
|
float f2 = (float)targetVal;
|
||||||
|
return Mathf.Abs(f1 - f2) < FloatEpsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 类型是 Vector3
|
||||||
|
if (t == typeof(Vector3))
|
||||||
|
{
|
||||||
|
Vector3 v1 = (Vector3)fieldVal;
|
||||||
|
Vector3 v2 = (Vector3)targetVal;
|
||||||
|
// 使用 Unity 的 Distance 容差比较
|
||||||
|
return Vector3.Distance(v1, v2) < FloatEpsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 类型是 Color
|
||||||
|
if (t == typeof(Color))
|
||||||
|
{
|
||||||
|
Color c1 = (Color)fieldVal;
|
||||||
|
Color c2 = (Color)targetVal;
|
||||||
|
|
||||||
|
// 手动解构 Color 的四个 float 分量,使用容差
|
||||||
|
return Mathf.Abs(c1.r - c2.r) < FloatEpsilon &&
|
||||||
|
Mathf.Abs(c1.g - c2.g) < FloatEpsilon &&
|
||||||
|
Mathf.Abs(c1.b - c2.b) < FloatEpsilon &&
|
||||||
|
Mathf.Abs(c1.a - c2.a) < FloatEpsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 其他包含 float 的复杂 Struct/Class 的浅层解构
|
||||||
|
if (!t.IsPrimitive && t != typeof(string) && (t.IsClass || t.IsValueType))
|
||||||
|
{
|
||||||
|
// 如果字段值是复杂类型,并且我们想比较它的内部 float 字段 (浅层)
|
||||||
|
// 这里只能进行浅层比较,因为深层递归需要辅助函数来管理栈。
|
||||||
|
|
||||||
|
// 遍历所有顶层字段,检查是否有 float
|
||||||
|
foreach (var field in t.GetFields(DeepMatchFlags))
|
||||||
|
{
|
||||||
|
object fieldValMember = field.GetValue(fieldVal);
|
||||||
|
object targetValMember = field.GetValue(targetVal);
|
||||||
|
|
||||||
|
if (field.FieldType == typeof(float))
|
||||||
|
{
|
||||||
|
// 对 float 成员进行容差比较
|
||||||
|
if (fieldValMember != null && targetValMember != null)
|
||||||
|
{
|
||||||
|
float f1 = (float)fieldValMember;
|
||||||
|
float f2 = (float)targetValMember;
|
||||||
|
if (Mathf.Abs(f1 - f2) >= FloatEpsilon)
|
||||||
|
{
|
||||||
|
return false; // 找到不匹配的 float
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fieldValMember != targetValMember) // 检查是否一个为 null,另一个不为 null
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 对其他类型使用默认 Equals
|
||||||
|
if (!fieldValMember.Equals(targetValMember))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 所有字段都匹配
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 默认路径:对于所有其他类型(int, string, bool, etc.),使用默认的 Equals 比较
|
||||||
|
return fieldVal.Equals(targetVal);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,21 +113,19 @@ namespace Ichni.RhythmGame
|
|||||||
}
|
}
|
||||||
namespace Ichni.Editor
|
namespace Ichni.Editor
|
||||||
{
|
{
|
||||||
public class TagManager : IBaseElement//这玩意大概不需要分BM的
|
public class TagManager : IBaseElement
|
||||||
{
|
{
|
||||||
|
// ... (你的原有代码: matchedBM, 构造函数等保持不变) ...
|
||||||
public BaseElement_BM matchedBM { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
public BaseElement_BM matchedBM { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||||
|
|
||||||
public List<TagMatcher> tagMatchers;
|
public List<TagMatcher> tagMatchers;
|
||||||
|
|
||||||
public TagManager()
|
public TagManager()
|
||||||
{
|
{
|
||||||
tagMatchers = new List<TagMatcher>();
|
tagMatchers = new List<TagMatcher>();
|
||||||
tempTagMatcherName = "";
|
// ...
|
||||||
tempElementTypeName = "";
|
|
||||||
tempParameterName = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ... (Add/Remove 方法保持不变) ...
|
||||||
public void AddTagMatcher(string name, Type elementType, string parameterName)
|
public void AddTagMatcher(string name, Type elementType, string parameterName)
|
||||||
{
|
{
|
||||||
//check
|
//check
|
||||||
@@ -161,51 +159,53 @@ namespace Ichni.Editor
|
|||||||
{
|
{
|
||||||
RemoveTagMatcher(tagMatchers.First(i => i.name == o));
|
RemoveTagMatcher(tagMatchers.First(i => i.name == o));
|
||||||
}
|
}
|
||||||
|
// ... 其他 Add/Remove ...
|
||||||
|
|
||||||
public List<IBaseElement> GetMachedElements(TagMatcher o)
|
public List<IBaseElement> GetMachedElements(TagMatcher o)
|
||||||
{
|
{
|
||||||
return EditorManager.instance.beatmapContainer.gameElementList
|
return EditorManager.instance.beatmapContainer.gameElementList
|
||||||
.Where(p => o.Match(p)).Cast<IBaseElement>().ToList();
|
.Where(p => o.Match(p)).Cast<IBaseElement>().ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TagMatcher> GetMatcher(GameElement baseElement)
|
public List<TagMatcher> GetMatcher(GameElement baseElement)
|
||||||
{
|
{
|
||||||
return tagMatchers.Where(p => p.Match(baseElement)).ToList();
|
return tagMatchers.Where(p => p.Match(baseElement)).ToList();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 修改 1: 使用 ReflectionHelper 设置值 ---
|
||||||
public void SetMatchedElements(TagMatcher o, object value)
|
public void SetMatchedElements(TagMatcher o, object value)
|
||||||
{
|
{
|
||||||
foreach (var i in GetMachedElements(o))
|
foreach (var i in GetMachedElements(o))
|
||||||
{
|
{
|
||||||
|
// 直接调用修改后的 SetValue
|
||||||
o.SetValue(i, value);
|
o.SetValue(i, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 修改 2: 使用 ReflectionHelper 同步值 ---
|
||||||
public void SyncTagedElement(GameElement gameElement)
|
public void SyncTagedElement(GameElement gameElement)
|
||||||
{
|
{
|
||||||
foreach (var matcher in GetMatcher(gameElement))
|
foreach (var matcher in GetMatcher(gameElement))
|
||||||
{
|
{
|
||||||
var matchedElements = GetMachedElements(matcher);
|
var matchedElements = GetMachedElements(matcher);
|
||||||
|
|
||||||
|
// A. 获取源值 (使用 ReflectionHelper 以支持嵌套路径,如 "transform.position")
|
||||||
|
var value = ReflectionHelper.GetDeepValue(gameElement, matcher.parameterName);
|
||||||
|
|
||||||
foreach (var element in matchedElements)
|
foreach (var element in matchedElements)
|
||||||
{
|
{
|
||||||
var value = gameElement.GetType().GetField(matcher.parameterName).GetValue(gameElement);
|
// B. 设置目标值 (TagMatcher 内部现在使用 ReflectionHelper)
|
||||||
matcher.SetValue(element, value);
|
matcher.SetValue(element, value);
|
||||||
element.Refresh();
|
element.Refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void SetUpInspector()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public string tempTagMatcherName = "";
|
|
||||||
public string tempElementTypeName = "";
|
|
||||||
public string tempParameterName = "";
|
|
||||||
public void SetUpInspector()
|
|
||||||
{
|
{
|
||||||
tempTagMatcherName = "";
|
// tempTagMatcherName = "";
|
||||||
tempElementTypeName = "";
|
// tempElementTypeName = "";
|
||||||
tempParameterName = "";
|
// tempParameterName = "";
|
||||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||||
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
|
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
|
||||||
var container = inspector.GenerateContainer("Tag Manager");
|
var container = inspector.GenerateContainer("Tag Manager");
|
||||||
@@ -217,7 +217,11 @@ namespace Ichni.Editor
|
|||||||
var sub = container.GenerateSubcontainer(2);
|
var sub = container.GenerateSubcontainer(2);
|
||||||
inspector.GenerateHintText(this, sub, $"Name: {matcher.name}");
|
inspector.GenerateHintText(this, sub, $"Name: {matcher.name}");
|
||||||
inspector.GenerateHintText(this, sub, $"Type: {matcher.ElementType?.Name ?? "<null>"}");
|
inspector.GenerateHintText(this, sub, $"Type: {matcher.ElementType?.Name ?? "<null>"}");
|
||||||
inspector.GenerateHintText(this, sub, $"Param: {matcher.parameterName}");
|
var e = inspector.GenerateInputField(sub, "Parameter", matcher.parameterName);
|
||||||
|
e.AddListenerFunction(() =>
|
||||||
|
{
|
||||||
|
matcher.parameterName = e.inputField.text;
|
||||||
|
});
|
||||||
inspector.GenerateButton(this, sub, "Remove", () =>
|
inspector.GenerateButton(this, sub, "Remove", () =>
|
||||||
{
|
{
|
||||||
RemoveTagMatcher(matcher);
|
RemoveTagMatcher(matcher);
|
||||||
@@ -225,86 +229,96 @@ namespace Ichni.Editor
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增TagMatcher区域
|
// // 新增TagMatcher区域
|
||||||
var addSub = container.GenerateSubcontainer(3);
|
// var addSub = container.GenerateSubcontainer(3);
|
||||||
// 输入Tag名称
|
// // 输入Tag名称
|
||||||
var nameInput = inspector.GenerateInputField(this, addSub, "Tag Name", nameof(tempTagMatcherName));
|
// var nameInput = inspector.GenerateInputField(this, addSub, "Tag Name", nameof(tempTagMatcherName));
|
||||||
// 下拉选择类型
|
// // 下拉选择类型
|
||||||
List<Type> typeList = TypeHelper.GetInheritedTypes<GameElement>();
|
// List<Type> typeList = TypeHelper.GetInheritedTypes<GameElement>();
|
||||||
List<string> typeNames = typeList.ConvertAll(t => t.FullName);
|
// List<string> typeNames = typeList.ConvertAll(t => t.FullName);
|
||||||
var typeDropdown = inspector.GenerateDropdown(this, addSub, "Element Type", typeNames, nameof(tempElementTypeName))
|
// var typeDropdown = inspector.GenerateDropdown(this, addSub, "Element Type", typeNames, nameof(tempElementTypeName))
|
||||||
.AddListenerFunction(() =>
|
// .AddListenerFunction(() =>
|
||||||
{
|
// {
|
||||||
// 选择类型后刷新参数下拉
|
// // 选择类型后刷新参数下拉
|
||||||
Type selectedType = typeList.FirstOrDefault(t => t.FullName == tempElementTypeName);
|
// Type selectedType = typeList.FirstOrDefault(t => t.FullName == tempElementTypeName);
|
||||||
List<string> paramNames = selectedType != null
|
// List<string> paramNames = selectedType != null
|
||||||
? selectedType.GetFields().Select(f => f.Name).ToList()
|
// ? selectedType.GetFields().Select(f => f.Name).ToList()
|
||||||
: new List<string>();
|
// : new List<string>();
|
||||||
//inspector.GenerateDropdown(this, addSub, "Parameter", paramNames, nameof(tempParameterName));
|
// //inspector.GenerateDropdown(this, addSub, "Parameter", paramNames, nameof(tempParameterName));
|
||||||
});
|
// });
|
||||||
|
|
||||||
// 参数下拉(初始为空,随类型变化刷新)
|
// 参数下拉(初始为空,随类型变化刷新)
|
||||||
if (!string.IsNullOrEmpty(tempElementTypeName))
|
// if (!string.IsNullOrEmpty(tempElementTypeName))
|
||||||
{
|
// {
|
||||||
Type selectedType = typeList.FirstOrDefault(t => t.FullName == tempElementTypeName);
|
// Type selectedType = typeList.FirstOrDefault(t => t.FullName == tempElementTypeName);
|
||||||
List<string> paramNames = selectedType != null
|
// List<string> paramNames = selectedType != null
|
||||||
? selectedType.GetFields().Select(f => f.Name).ToList()
|
// ? selectedType.GetFields().Select(f => f.Name).ToList()
|
||||||
: new List<string>();
|
// : new List<string>();
|
||||||
inspector.GenerateDropdown(this, addSub, "Parameter", paramNames, nameof(tempParameterName));
|
// inspector.GenerateDropdown(this, addSub, "Parameter", paramNames, nameof(tempParameterName));
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
inspector.GenerateDropdown(this, addSub, "Parameter", new List<string>(), nameof(tempParameterName));
|
// inspector.GenerateDropdown(this, addSub, "Parameter", new List<string>(), nameof(tempParameterName));
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 添加按钮
|
// // 添加按钮
|
||||||
var addButton = inspector.GenerateButton(this, addSub, "Add TagMatcher", () =>
|
// var addButton = inspector.GenerateButton(this, addSub, "Add TagMatcher", () =>
|
||||||
{
|
// {
|
||||||
if (string.IsNullOrEmpty(tempTagMatcherName) || string.IsNullOrEmpty(tempElementTypeName) || string.IsNullOrEmpty(tempParameterName))
|
// if (string.IsNullOrEmpty(tempTagMatcherName) || string.IsNullOrEmpty(tempElementTypeName) || string.IsNullOrEmpty(tempParameterName))
|
||||||
{
|
// {
|
||||||
Debug.LogWarning("请填写完整信息再添加TagMatcher。");
|
// Debug.LogWarning("请填写完整信息再添加TagMatcher。");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
if (tagMatchers.Any(t => t.name == tempTagMatcherName))
|
// if (tagMatchers.Any(t => t.name == tempTagMatcherName))
|
||||||
{
|
// {
|
||||||
Debug.LogWarning("TagMatcher's name is repeated!");
|
// Debug.LogWarning("TagMatcher's name is repeated!");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
Type selectedType = typeList.FirstOrDefault(t => t.FullName == tempElementTypeName);
|
// Type selectedType = typeList.FirstOrDefault(t => t.FullName == tempElementTypeName);
|
||||||
TagMatcher matcher = new TagMatcher
|
// TagMatcher matcher = new TagMatcher
|
||||||
{
|
// {
|
||||||
name = tempTagMatcherName,
|
// name = tempTagMatcherName,
|
||||||
ElementType = selectedType,
|
// ElementType = selectedType,
|
||||||
parameterName = tempParameterName
|
// parameterName = tempParameterName
|
||||||
};
|
// };
|
||||||
AddTagMatcher(matcher);
|
// AddTagMatcher(matcher);
|
||||||
inspectorMain.SetInspector(EditorManager.instance.projectInformation);
|
// inspectorMain.SetInspector(EditorManager.instance.projectInformation);
|
||||||
});
|
// });
|
||||||
|
|
||||||
// 按需禁用添加按钮
|
// // 按需禁用添加按钮
|
||||||
if (string.IsNullOrEmpty(tempTagMatcherName) || string.IsNullOrEmpty(tempElementTypeName) || string.IsNullOrEmpty(tempParameterName))
|
// if (string.IsNullOrEmpty(tempTagMatcherName) || string.IsNullOrEmpty(tempElementTypeName) || string.IsNullOrEmpty(tempParameterName))
|
||||||
{
|
// {
|
||||||
addButton.button.interactable = false;
|
// addButton.button.interactable = false;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ... (Inspector 变量保持不变) ...
|
||||||
|
|
||||||
|
|
||||||
public struct TagMatcher
|
public struct TagMatcher
|
||||||
{
|
{
|
||||||
public string name;
|
public string name;
|
||||||
public Type ElementType;
|
public Type ElementType;
|
||||||
public string parameterName;
|
public string parameterName; // 现在可以填 "transform.position.x" 这种路径了
|
||||||
|
|
||||||
public readonly bool Match(GameElement gameElement)
|
public readonly bool Match(GameElement gameElement)
|
||||||
{
|
{
|
||||||
string o = name;
|
string o = name;
|
||||||
return gameElement.tags.Any(i => i == o);
|
// 注意:这里建议加空检查,防止 gameElement.tags 为 null
|
||||||
|
return gameElement.tags != null && gameElement.tags.Any(i => i == o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 修改 3: TagMatcher 内部逻辑更新 ---
|
||||||
public readonly void SetValue(IBaseElement baseElement, object value)
|
public readonly void SetValue(IBaseElement baseElement, object value)
|
||||||
{
|
{
|
||||||
if (ElementType != baseElement.GetType()) return;
|
// 原有逻辑:严格检查类型
|
||||||
ElementType.GetField(parameterName).SetValue(baseElement, value);
|
// if (ElementType != baseElement.GetType()) return;
|
||||||
|
|
||||||
|
// 新逻辑建议:
|
||||||
|
// 1. 既然是用 Tag 匹配,不同类可能有相同的字段名 (鸭子类型),去掉严格类型检查可能更灵活。
|
||||||
|
// 2. 如果必须检查,保留上面那行。
|
||||||
|
|
||||||
|
// 使用 ReflectionHelper 处理赋值 (自动处理 Struct 回写和嵌套)
|
||||||
|
ReflectionHelper.SetDeepValue(baseElement, parameterName, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,13 @@ namespace Ichni.RhythmGame
|
|||||||
new List<string>(), true, this, 1000f));
|
new List<string>(), true, this, 1000f));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
public override void OnDelete()
|
||||||
|
{
|
||||||
|
if (cameraManager.gameCamera == this)
|
||||||
|
{
|
||||||
|
cameraManager.SwitchCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class GameCamera
|
public partial class GameCamera
|
||||||
|
|||||||
325
Assets/Scripts/Extensions/ReflectionHelper.cs
Normal file
325
Assets/Scripts/Extensions/ReflectionHelper.cs
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public static class ReflectionHelper
|
||||||
|
{
|
||||||
|
private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||||
|
|
||||||
|
// --- 设置值 (支持 object) ---
|
||||||
|
public static void SetDeepValue(object target, string path, object newValue)
|
||||||
|
{
|
||||||
|
if (target == null || string.IsNullOrEmpty(path)) return;
|
||||||
|
string[] parts = path.Split('.');
|
||||||
|
SetDeepValueRecursive(target, parts, 0, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetDeepValueRecursive(object currentObj, string[] pathParts, int index, object newValue)
|
||||||
|
{
|
||||||
|
string memberName = pathParts[index];
|
||||||
|
Type type = currentObj.GetType();
|
||||||
|
|
||||||
|
FieldInfo field = type.GetField(memberName, Flags);
|
||||||
|
PropertyInfo prop = type.GetProperty(memberName, Flags);
|
||||||
|
|
||||||
|
if (field == null && prop == null)
|
||||||
|
{
|
||||||
|
// Debug.LogWarning($"找不到成员: {memberName}"); // 可选:调试用
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isLast = index == pathParts.Length - 1;
|
||||||
|
|
||||||
|
if (isLast)
|
||||||
|
{
|
||||||
|
// 到达终点:直接设置值
|
||||||
|
// 注意:这里可能需要处理类型转换,取决于你的 newValue 类型是否严格匹配
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (field != null) field.SetValue(currentObj, newValue);
|
||||||
|
else if (prop != null && prop.CanWrite) prop.SetValue(currentObj, newValue);
|
||||||
|
}
|
||||||
|
catch (Exception e) { Debug.LogError($"设置值失败 {memberName}: {e.Message}"); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 中间节点
|
||||||
|
object nextObj = field != null ? field.GetValue(currentObj) : prop.GetValue(currentObj);
|
||||||
|
if (nextObj == null) return;
|
||||||
|
|
||||||
|
SetDeepValueRecursive(nextObj, pathParts, index + 1, newValue);
|
||||||
|
|
||||||
|
// Struct 回写逻辑 (关键)
|
||||||
|
if (nextObj.GetType().IsValueType)
|
||||||
|
{
|
||||||
|
if (field != null) field.SetValue(currentObj, nextObj);
|
||||||
|
else if (prop != null && prop.CanWrite) prop.SetValue(currentObj, nextObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 获取值 (支持 object) ---
|
||||||
|
public static object GetDeepValue(object target, string path)
|
||||||
|
{
|
||||||
|
object current = target;
|
||||||
|
foreach (string part in path.Split('.'))
|
||||||
|
{
|
||||||
|
if (current == null) return null;
|
||||||
|
Type type = current.GetType();
|
||||||
|
|
||||||
|
FieldInfo field = type.GetField(part, Flags);
|
||||||
|
if (field != null)
|
||||||
|
{
|
||||||
|
current = field.GetValue(current);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyInfo prop = type.GetProperty(part, Flags);
|
||||||
|
if (prop != null)
|
||||||
|
{
|
||||||
|
current = prop.GetValue(current);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return null; // 路径中断
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 遍历对象的所有字段和属性(递归地),查找值与目标值匹配的参数路径。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">要搜索的对象实例。</param>
|
||||||
|
/// <param name="targetValue">要匹配的目标值。</param>
|
||||||
|
/// <param name="maxDepth">递归搜索的最大深度,防止无限循环。</param>
|
||||||
|
/// <returns>返回匹配参数的完整路径列表 (例如: "position.x")。</returns>
|
||||||
|
public static List<string> FindParametersByValue(object target, object targetValue, int maxDepth = 10)
|
||||||
|
{
|
||||||
|
if (target == null || targetValue == null) return new List<string>();
|
||||||
|
|
||||||
|
// 用于存储找到的路径
|
||||||
|
var results = new List<string>();
|
||||||
|
|
||||||
|
// 用于防止循环引用(比如类 A 内部引用了类 B,类 B 内部又引用了类 A)
|
||||||
|
var visited = new HashSet<object>();
|
||||||
|
|
||||||
|
// 启动递归搜索
|
||||||
|
FindRecursive(target, targetValue, "", 0, results, visited, maxDepth);
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FindRecursive(
|
||||||
|
object currentObject,
|
||||||
|
object targetValue,
|
||||||
|
string currentPath,
|
||||||
|
int depth,
|
||||||
|
List<string> results,
|
||||||
|
HashSet<object> visited,
|
||||||
|
int maxDepth)
|
||||||
|
{
|
||||||
|
if (currentObject == null || depth >= maxDepth) return;
|
||||||
|
|
||||||
|
// 避免无限循环和重复搜索
|
||||||
|
// 对于值类型 (Struct) 不需要加入 visited,因为它们是副本
|
||||||
|
if (!currentObject.GetType().IsValueType)
|
||||||
|
{
|
||||||
|
// 如果对象已经被搜索过,则跳过
|
||||||
|
if (visited.Contains(currentObject)) return;
|
||||||
|
visited.Add(currentObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type currentType = currentObject.GetType();
|
||||||
|
|
||||||
|
// 1. 遍历 Field 字段
|
||||||
|
foreach (var field in currentType.GetFields(Flags))
|
||||||
|
{
|
||||||
|
// 跳过内部字段,如编译器生成的 backing fields
|
||||||
|
if (field.IsDefined(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), false)) continue;
|
||||||
|
|
||||||
|
object value = field.GetValue(currentObject);
|
||||||
|
string newPath = string.IsNullOrEmpty(currentPath) ? field.Name : $"{currentPath}.{field.Name}";
|
||||||
|
|
||||||
|
CheckAndRecurse(field.FieldType, value, targetValue, newPath, depth, results, visited, maxDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 遍历 Property 属性
|
||||||
|
foreach (var prop in currentType.GetProperties(Flags).Where(p => p.CanRead))
|
||||||
|
{
|
||||||
|
// 跳过索引器
|
||||||
|
if (prop.GetIndexParameters().Length > 0) continue;
|
||||||
|
|
||||||
|
object value = prop.GetValue(currentObject);
|
||||||
|
string newPath = string.IsNullOrEmpty(currentPath) ? prop.Name : $"{currentPath}.{prop.Name}";
|
||||||
|
|
||||||
|
CheckAndRecurse(prop.PropertyType, value, targetValue, newPath, depth, results, visited, maxDepth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查当前值是否匹配,如果不是基础类型则继续递归
|
||||||
|
/// </summary>
|
||||||
|
private static void CheckAndRecurse(
|
||||||
|
Type valueType,
|
||||||
|
object value,
|
||||||
|
object targetValue,
|
||||||
|
string newPath,
|
||||||
|
int depth,
|
||||||
|
List<string> results,
|
||||||
|
HashSet<object> visited,
|
||||||
|
int maxDepth)
|
||||||
|
{
|
||||||
|
if (value == null) return;
|
||||||
|
|
||||||
|
// 【值匹配检查】
|
||||||
|
if (value.Equals(targetValue))
|
||||||
|
{
|
||||||
|
results.Add(newPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【递归检查】
|
||||||
|
// 只有当值是一个复杂类型(Class 或 Struct)时才需要递归
|
||||||
|
// 排除字符串和集合(List, Array等,如果你需要搜索集合内部,逻辑会更复杂)
|
||||||
|
if (valueType.IsClass || valueType.IsValueType && !valueType.IsPrimitive)
|
||||||
|
{
|
||||||
|
// 排除 String (虽然是 Class,但我们视其为基础值)
|
||||||
|
if (valueType == typeof(string)) return;
|
||||||
|
|
||||||
|
// 排除集合(如果需要支持 List<T> 的内部搜索,你需要在这里添加处理逻辑)
|
||||||
|
if (valueType.IsArray || valueType.IsGenericType && valueType.GetInterfaces().Any(i => i == typeof(System.Collections.IEnumerable))) return;
|
||||||
|
|
||||||
|
// 递归进入下一层
|
||||||
|
FindRecursive(value, targetValue, newPath, depth + 1, results, visited, maxDepth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class FastReflection
|
||||||
|
{
|
||||||
|
// 定义一个节点,用来缓存每一层的 Field 或 Property 信息
|
||||||
|
private class MemberNode
|
||||||
|
{
|
||||||
|
public FieldInfo Field;
|
||||||
|
public PropertyInfo Property;
|
||||||
|
public bool IsField => Field != null;
|
||||||
|
|
||||||
|
public MemberNode(MemberInfo info)
|
||||||
|
{
|
||||||
|
if (info is FieldInfo f) Field = f;
|
||||||
|
else if (info is PropertyInfo p) Property = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 快速获取值
|
||||||
|
public object GetValue(object target)
|
||||||
|
{
|
||||||
|
return IsField ? Field.GetValue(target) : Property.GetValue(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 快速设置值
|
||||||
|
public void SetValue(object target, object value)
|
||||||
|
{
|
||||||
|
if (IsField) Field.SetValue(target, value);
|
||||||
|
else if (Property != null && Property.CanWrite) Property.SetValue(target, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断这一层是否是 Struct (值类型),如果是,修改后需要回写
|
||||||
|
public bool IsStructType()
|
||||||
|
{
|
||||||
|
return IsField ? Field.FieldType.IsValueType : Property.PropertyType.IsValueType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 访问器链条
|
||||||
|
private readonly List<MemberNode> _nodes = new List<MemberNode>();
|
||||||
|
private bool _isValid = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数:初始化时进行昂贵的解析操作(只做一次)
|
||||||
|
/// </summary>
|
||||||
|
public FastReflection(object rootTarget, string path)
|
||||||
|
{
|
||||||
|
if (rootTarget == null || string.IsNullOrEmpty(path)) return;
|
||||||
|
|
||||||
|
Type currentType = rootTarget.GetType();
|
||||||
|
string[] parts = path.Split('.');
|
||||||
|
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||||
|
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
// 查找字段或属性
|
||||||
|
FieldInfo field = currentType.GetField(part, flags);
|
||||||
|
PropertyInfo prop = currentType.GetProperty(part, flags);
|
||||||
|
|
||||||
|
if (field == null && prop == null)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[FastReflection] 路径中断: 找不到成员 '{part}' 在类型 '{currentType.Name}' 中");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建节点并添加到链条
|
||||||
|
MemberNode node = new MemberNode(field ?? (MemberInfo)prop);
|
||||||
|
_nodes.Add(node);
|
||||||
|
|
||||||
|
// 更新 currentType 为下一层的类型
|
||||||
|
currentType = field != null ? field.FieldType : prop.PropertyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取值(运行时极快)
|
||||||
|
/// </summary>
|
||||||
|
public float GetValue(object rootTarget)
|
||||||
|
{
|
||||||
|
if (!_isValid) return 0f;
|
||||||
|
|
||||||
|
object current = rootTarget;
|
||||||
|
for (int i = 0; i < _nodes.Count; i++)
|
||||||
|
{
|
||||||
|
current = _nodes[i].GetValue(current);
|
||||||
|
if (current == null) return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (float)current; // 假设最后一定是 float
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置值(运行时极快,自动处理 Struct 回写)
|
||||||
|
/// </summary>
|
||||||
|
public void SetValue(object rootTarget, float newValue)
|
||||||
|
{
|
||||||
|
if (!_isValid) return;
|
||||||
|
|
||||||
|
// 开始递归处理回写
|
||||||
|
SetRecursive(rootTarget, 0, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归函数:处理“获取-修改-回写”逻辑
|
||||||
|
private void SetRecursive(object currentObj, int index, float finalValue)
|
||||||
|
{
|
||||||
|
MemberNode node = _nodes[index];
|
||||||
|
|
||||||
|
// 1. 如果是链条的最后一个节点(即那个 float 变量)
|
||||||
|
if (index == _nodes.Count - 1)
|
||||||
|
{
|
||||||
|
node.SetValue(currentObj, finalValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 如果是中间节点,先获取下一层对象
|
||||||
|
object nextObj = node.GetValue(currentObj);
|
||||||
|
if (nextObj == null) return;
|
||||||
|
|
||||||
|
// 3. 递归进入下一层
|
||||||
|
SetRecursive(nextObj, index + 1, finalValue);
|
||||||
|
|
||||||
|
// 4. 【关键】回写阶段
|
||||||
|
// 如果 nextObj 是 Struct(值类型),比如 Vector3,
|
||||||
|
// 我们刚才在递归里修改了 nextObj 的副本,现在必须把它赋值回 currentObj
|
||||||
|
if (node.IsStructType())
|
||||||
|
{
|
||||||
|
node.SetValue(currentObj, nextObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/Scripts/Extensions/ReflectionHelper.cs.meta
Normal file
11
Assets/Scripts/Extensions/ReflectionHelper.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d8465d62ddf65c945924e35a0c1851ac
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -40,8 +40,7 @@ namespace Ichni.RhythmGame
|
|||||||
if (shouldBeActive && !isActive)
|
if (shouldBeActive && !isActive)
|
||||||
{
|
{
|
||||||
note.gameObject.SetActive(true);
|
note.gameObject.SetActive(true);
|
||||||
note.Update();
|
if (currentTime < note.exactJudgeTime) note.noteVisual?.Recover();
|
||||||
if (!note.isFirstJudged) note.noteVisual?.Recover();
|
|
||||||
}
|
}
|
||||||
else if (!shouldBeActive && isActive)
|
else if (!shouldBeActive && isActive)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 0.5,
|
"shadowSmoothness" : 0.5,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : true,
|
"useWorldLight" : true,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -185,7 +185,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 0.5,
|
"shadowSmoothness" : 0.5,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -492,7 +492,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -562,7 +562,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -632,7 +632,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -702,7 +702,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -772,7 +772,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -842,7 +842,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -1264,8 +1264,8 @@
|
|||||||
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
"originalPosition" : {
|
"originalPosition" : {
|
||||||
"x" : 2.2,
|
"x" : 2.2,
|
||||||
"y" : 15,
|
"y" : 0,
|
||||||
"z" : 100
|
"z" : 0
|
||||||
},
|
},
|
||||||
"originalEulerAngles" : {
|
"originalEulerAngles" : {
|
||||||
"x" : 0,
|
"x" : 0,
|
||||||
@@ -1307,6 +1307,186 @@
|
|||||||
"attachedElementGuid" : {
|
"attachedElementGuid" : {
|
||||||
"value" : "5166eb6a-fbee-4c1a-a6d8-d8e263516e46"
|
"value" : "5166eb6a-fbee-4c1a-a6d8-d8e263516e46"
|
||||||
}
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.ElementFolder_BM,Assembly-CSharp",
|
||||||
|
"elementName" : "Folder",
|
||||||
|
"tags" : [
|
||||||
|
|
||||||
|
],
|
||||||
|
"elementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "00000000-0000-0000-0000-000000000000"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalPosition" : {
|
||||||
|
"x" : -15,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalEulerAngles" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalScale" : {
|
||||||
|
"x" : 1,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : 1
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TimeDurationSubmodule_BM,Assembly-CSharp",
|
||||||
|
"isOverridingDuration" : false,
|
||||||
|
"startTime" : -32767,
|
||||||
|
"endTime" : 32767,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
|
"shadowThreshold" : 0.2,
|
||||||
|
"shadowSmoothness" : 0.5,
|
||||||
|
"useWorldLight" : true,
|
||||||
|
"fakeLightDir" : {
|
||||||
|
"x" : 0.5,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : -0.5
|
||||||
|
},
|
||||||
|
"isStatic" : false,
|
||||||
|
"themeBundleName" : "basic",
|
||||||
|
"objectName" : "Capsule",
|
||||||
|
"elementName" : "New Environment Object",
|
||||||
|
"tags" : [
|
||||||
|
"sad"
|
||||||
|
],
|
||||||
|
"elementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalPosition" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 2.222,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalEulerAngles" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalScale" : {
|
||||||
|
"x" : 1,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : 1
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TimeDurationSubmodule_BM,Assembly-CSharp",
|
||||||
|
"isOverridingDuration" : false,
|
||||||
|
"startTime" : -32767,
|
||||||
|
"endTime" : 32767,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.ColorSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalBaseColor" : {
|
||||||
|
"r" : 1,
|
||||||
|
"g" : 1,
|
||||||
|
"b" : 1,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"emissionEnabled" : false,
|
||||||
|
"originalEmissionColor" : {
|
||||||
|
"r" : 0,
|
||||||
|
"g" : 0,
|
||||||
|
"b" : 0,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"originalEmissionIntensity" : 0,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
|
"shadowThreshold" : 0.2,
|
||||||
|
"shadowSmoothness" : 0.5,
|
||||||
|
"useWorldLight" : true,
|
||||||
|
"fakeLightDir" : {
|
||||||
|
"x" : -0.5,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : -0.5
|
||||||
|
},
|
||||||
|
"isStatic" : false,
|
||||||
|
"themeBundleName" : "basic",
|
||||||
|
"objectName" : "Capsule",
|
||||||
|
"elementName" : "New Environment Object",
|
||||||
|
"tags" : [
|
||||||
|
"sad"
|
||||||
|
],
|
||||||
|
"elementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalPosition" : {
|
||||||
|
"x" : 5,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalEulerAngles" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalScale" : {
|
||||||
|
"x" : 1,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : 1
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TimeDurationSubmodule_BM,Assembly-CSharp",
|
||||||
|
"isOverridingDuration" : false,
|
||||||
|
"startTime" : -32767,
|
||||||
|
"endTime" : 32767,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.ColorSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalBaseColor" : {
|
||||||
|
"r" : 0.956280768,
|
||||||
|
"g" : 0.676615953,
|
||||||
|
"b" : 1,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"emissionEnabled" : false,
|
||||||
|
"originalEmissionColor" : {
|
||||||
|
"r" : 0.3649238,
|
||||||
|
"g" : 0,
|
||||||
|
"b" : 0,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"originalEmissionIntensity" : 0,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"attachedElementGuid" : {
|
"attachedElementGuid" : {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 0.5,
|
"shadowSmoothness" : 0.5,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : true,
|
"useWorldLight" : true,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -185,7 +185,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 0.5,
|
"shadowSmoothness" : 0.5,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -492,7 +492,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -562,7 +562,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -632,7 +632,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -702,7 +702,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -772,7 +772,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -842,7 +842,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -1264,8 +1264,8 @@
|
|||||||
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
"originalPosition" : {
|
"originalPosition" : {
|
||||||
"x" : 2.2,
|
"x" : 2.2,
|
||||||
"y" : 15,
|
"y" : 0,
|
||||||
"z" : 100
|
"z" : 0
|
||||||
},
|
},
|
||||||
"originalEulerAngles" : {
|
"originalEulerAngles" : {
|
||||||
"x" : 0,
|
"x" : 0,
|
||||||
@@ -1307,6 +1307,186 @@
|
|||||||
"attachedElementGuid" : {
|
"attachedElementGuid" : {
|
||||||
"value" : "5166eb6a-fbee-4c1a-a6d8-d8e263516e46"
|
"value" : "5166eb6a-fbee-4c1a-a6d8-d8e263516e46"
|
||||||
}
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.ElementFolder_BM,Assembly-CSharp",
|
||||||
|
"elementName" : "Folder",
|
||||||
|
"tags" : [
|
||||||
|
|
||||||
|
],
|
||||||
|
"elementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "00000000-0000-0000-0000-000000000000"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalPosition" : {
|
||||||
|
"x" : -15,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalEulerAngles" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalScale" : {
|
||||||
|
"x" : 1,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : 1
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TimeDurationSubmodule_BM,Assembly-CSharp",
|
||||||
|
"isOverridingDuration" : false,
|
||||||
|
"startTime" : -32767,
|
||||||
|
"endTime" : 32767,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
|
"shadowThreshold" : 0.2,
|
||||||
|
"shadowSmoothness" : 0.5,
|
||||||
|
"useWorldLight" : true,
|
||||||
|
"fakeLightDir" : {
|
||||||
|
"x" : 0.5,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : -0.5
|
||||||
|
},
|
||||||
|
"isStatic" : false,
|
||||||
|
"themeBundleName" : "basic",
|
||||||
|
"objectName" : "Capsule",
|
||||||
|
"elementName" : "New Environment Object",
|
||||||
|
"tags" : [
|
||||||
|
"sad"
|
||||||
|
],
|
||||||
|
"elementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalPosition" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 2.222,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalEulerAngles" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalScale" : {
|
||||||
|
"x" : 1,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : 1
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TimeDurationSubmodule_BM,Assembly-CSharp",
|
||||||
|
"isOverridingDuration" : false,
|
||||||
|
"startTime" : -32767,
|
||||||
|
"endTime" : 32767,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.ColorSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalBaseColor" : {
|
||||||
|
"r" : 1,
|
||||||
|
"g" : 1,
|
||||||
|
"b" : 1,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"emissionEnabled" : false,
|
||||||
|
"originalEmissionColor" : {
|
||||||
|
"r" : 0,
|
||||||
|
"g" : 0,
|
||||||
|
"b" : 0,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"originalEmissionIntensity" : 0,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
|
"shadowThreshold" : 0.2,
|
||||||
|
"shadowSmoothness" : 0.5,
|
||||||
|
"useWorldLight" : true,
|
||||||
|
"fakeLightDir" : {
|
||||||
|
"x" : -0.5,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : -0.5
|
||||||
|
},
|
||||||
|
"isStatic" : false,
|
||||||
|
"themeBundleName" : "basic",
|
||||||
|
"objectName" : "Capsule",
|
||||||
|
"elementName" : "New Environment Object",
|
||||||
|
"tags" : [
|
||||||
|
"sad"
|
||||||
|
],
|
||||||
|
"elementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalPosition" : {
|
||||||
|
"x" : 5,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalEulerAngles" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalScale" : {
|
||||||
|
"x" : 1,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : 1
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TimeDurationSubmodule_BM,Assembly-CSharp",
|
||||||
|
"isOverridingDuration" : false,
|
||||||
|
"startTime" : -32767,
|
||||||
|
"endTime" : 32767,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.ColorSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalBaseColor" : {
|
||||||
|
"r" : 0.956280768,
|
||||||
|
"g" : 0.676615953,
|
||||||
|
"b" : 1,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"emissionEnabled" : false,
|
||||||
|
"originalEmissionColor" : {
|
||||||
|
"r" : 0.3649238,
|
||||||
|
"g" : 0,
|
||||||
|
"b" : 0,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"originalEmissionIntensity" : 0,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"attachedElementGuid" : {
|
"attachedElementGuid" : {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 0.5,
|
"shadowSmoothness" : 0.5,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : true,
|
"useWorldLight" : true,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -185,7 +185,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 0.5,
|
"shadowSmoothness" : 0.5,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -492,7 +492,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -562,7 +562,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -632,7 +632,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -702,7 +702,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -772,7 +772,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -842,7 +842,7 @@
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
"shadowThreshold" : 0.2,
|
"shadowThreshold" : 0.1,
|
||||||
"shadowSmoothness" : 1,
|
"shadowSmoothness" : 1,
|
||||||
"useWorldLight" : false,
|
"useWorldLight" : false,
|
||||||
"fakeLightDir" : {
|
"fakeLightDir" : {
|
||||||
@@ -1264,8 +1264,8 @@
|
|||||||
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
"originalPosition" : {
|
"originalPosition" : {
|
||||||
"x" : 2.2,
|
"x" : 2.2,
|
||||||
"y" : 15,
|
"y" : 0,
|
||||||
"z" : 100
|
"z" : 0
|
||||||
},
|
},
|
||||||
"originalEulerAngles" : {
|
"originalEulerAngles" : {
|
||||||
"x" : 0,
|
"x" : 0,
|
||||||
@@ -1307,6 +1307,186 @@
|
|||||||
"attachedElementGuid" : {
|
"attachedElementGuid" : {
|
||||||
"value" : "5166eb6a-fbee-4c1a-a6d8-d8e263516e46"
|
"value" : "5166eb6a-fbee-4c1a-a6d8-d8e263516e46"
|
||||||
}
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.ElementFolder_BM,Assembly-CSharp",
|
||||||
|
"elementName" : "Folder",
|
||||||
|
"tags" : [
|
||||||
|
|
||||||
|
],
|
||||||
|
"elementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "00000000-0000-0000-0000-000000000000"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalPosition" : {
|
||||||
|
"x" : -15,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalEulerAngles" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalScale" : {
|
||||||
|
"x" : 1,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : 1
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TimeDurationSubmodule_BM,Assembly-CSharp",
|
||||||
|
"isOverridingDuration" : false,
|
||||||
|
"startTime" : -32767,
|
||||||
|
"endTime" : 32767,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
|
"shadowThreshold" : 0.2,
|
||||||
|
"shadowSmoothness" : 0.5,
|
||||||
|
"useWorldLight" : true,
|
||||||
|
"fakeLightDir" : {
|
||||||
|
"x" : 0.5,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : -0.5
|
||||||
|
},
|
||||||
|
"isStatic" : false,
|
||||||
|
"themeBundleName" : "basic",
|
||||||
|
"objectName" : "Capsule",
|
||||||
|
"elementName" : "New Environment Object",
|
||||||
|
"tags" : [
|
||||||
|
"sad"
|
||||||
|
],
|
||||||
|
"elementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalPosition" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 2.222,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalEulerAngles" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalScale" : {
|
||||||
|
"x" : 1,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : 1
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TimeDurationSubmodule_BM,Assembly-CSharp",
|
||||||
|
"isOverridingDuration" : false,
|
||||||
|
"startTime" : -32767,
|
||||||
|
"endTime" : 32767,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.ColorSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalBaseColor" : {
|
||||||
|
"r" : 1,
|
||||||
|
"g" : 1,
|
||||||
|
"b" : 1,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"emissionEnabled" : false,
|
||||||
|
"originalEmissionColor" : {
|
||||||
|
"r" : 0,
|
||||||
|
"g" : 0,
|
||||||
|
"b" : 0,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"originalEmissionIntensity" : 0,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
|
"shadowThreshold" : 0.2,
|
||||||
|
"shadowSmoothness" : 0.5,
|
||||||
|
"useWorldLight" : true,
|
||||||
|
"fakeLightDir" : {
|
||||||
|
"x" : -0.5,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : -0.5
|
||||||
|
},
|
||||||
|
"isStatic" : false,
|
||||||
|
"themeBundleName" : "basic",
|
||||||
|
"objectName" : "Capsule",
|
||||||
|
"elementName" : "New Environment Object",
|
||||||
|
"tags" : [
|
||||||
|
"sad"
|
||||||
|
],
|
||||||
|
"elementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalPosition" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 2.222,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalEulerAngles" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalScale" : {
|
||||||
|
"x" : 1,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : 1
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TimeDurationSubmodule_BM,Assembly-CSharp",
|
||||||
|
"isOverridingDuration" : false,
|
||||||
|
"startTime" : -32767,
|
||||||
|
"endTime" : 32767,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.ColorSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalBaseColor" : {
|
||||||
|
"r" : 0.956280768,
|
||||||
|
"g" : 0.676615953,
|
||||||
|
"b" : 1,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"emissionEnabled" : false,
|
||||||
|
"originalEmissionColor" : {
|
||||||
|
"r" : 0.3649238,
|
||||||
|
"g" : 0,
|
||||||
|
"b" : 0,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"originalEmissionIntensity" : 0,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"attachedElementGuid" : {
|
"attachedElementGuid" : {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1307,6 +1307,186 @@
|
|||||||
"attachedElementGuid" : {
|
"attachedElementGuid" : {
|
||||||
"value" : "5166eb6a-fbee-4c1a-a6d8-d8e263516e46"
|
"value" : "5166eb6a-fbee-4c1a-a6d8-d8e263516e46"
|
||||||
}
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.ElementFolder_BM,Assembly-CSharp",
|
||||||
|
"elementName" : "Folder",
|
||||||
|
"tags" : [
|
||||||
|
|
||||||
|
],
|
||||||
|
"elementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "00000000-0000-0000-0000-000000000000"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalPosition" : {
|
||||||
|
"x" : -15,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalEulerAngles" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalScale" : {
|
||||||
|
"x" : 1,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : 1
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TimeDurationSubmodule_BM,Assembly-CSharp",
|
||||||
|
"isOverridingDuration" : false,
|
||||||
|
"startTime" : -32767,
|
||||||
|
"endTime" : 32767,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
|
"shadowThreshold" : 0.2,
|
||||||
|
"shadowSmoothness" : 0.5,
|
||||||
|
"useWorldLight" : true,
|
||||||
|
"fakeLightDir" : {
|
||||||
|
"x" : 0.5,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : -0.5
|
||||||
|
},
|
||||||
|
"isStatic" : false,
|
||||||
|
"themeBundleName" : "basic",
|
||||||
|
"objectName" : "Capsule",
|
||||||
|
"elementName" : "New Environment Object",
|
||||||
|
"tags" : [
|
||||||
|
"sad"
|
||||||
|
],
|
||||||
|
"elementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalPosition" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 2.222,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalEulerAngles" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalScale" : {
|
||||||
|
"x" : 1,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : 1
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TimeDurationSubmodule_BM,Assembly-CSharp",
|
||||||
|
"isOverridingDuration" : false,
|
||||||
|
"startTime" : -32767,
|
||||||
|
"endTime" : 32767,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.ColorSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalBaseColor" : {
|
||||||
|
"r" : 1,
|
||||||
|
"g" : 1,
|
||||||
|
"b" : 1,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"emissionEnabled" : false,
|
||||||
|
"originalEmissionColor" : {
|
||||||
|
"r" : 0,
|
||||||
|
"g" : 0,
|
||||||
|
"b" : 0,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"originalEmissionIntensity" : 0,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "bc6aed7f-bb86-43da-a59c-b1a7bfe99dea"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Beatmap.BasicEnvironmentObject_BM,Assembly-CSharp",
|
||||||
|
"shadowThreshold" : 0.2,
|
||||||
|
"shadowSmoothness" : 0.5,
|
||||||
|
"useWorldLight" : true,
|
||||||
|
"fakeLightDir" : {
|
||||||
|
"x" : -0.5,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : -0.5
|
||||||
|
},
|
||||||
|
"isStatic" : false,
|
||||||
|
"themeBundleName" : "basic",
|
||||||
|
"objectName" : "Capsule",
|
||||||
|
"elementName" : "New Environment Object",
|
||||||
|
"tags" : [
|
||||||
|
"sad"
|
||||||
|
],
|
||||||
|
"elementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "f9731a32-4e6d-4fb4-8d69-0fddc1cab743"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TransformSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalPosition" : {
|
||||||
|
"x" : 5,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalEulerAngles" : {
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0
|
||||||
|
},
|
||||||
|
"originalScale" : {
|
||||||
|
"x" : 1,
|
||||||
|
"y" : 1,
|
||||||
|
"z" : 1
|
||||||
|
},
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.TimeDurationSubmodule_BM,Assembly-CSharp",
|
||||||
|
"isOverridingDuration" : false,
|
||||||
|
"startTime" : -32767,
|
||||||
|
"endTime" : 32767,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"__type" : "Ichni.RhythmGame.Beatmap.ColorSubmodule_BM,Assembly-CSharp",
|
||||||
|
"originalBaseColor" : {
|
||||||
|
"r" : 0.956280768,
|
||||||
|
"g" : 0.676615953,
|
||||||
|
"b" : 1,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"emissionEnabled" : false,
|
||||||
|
"originalEmissionColor" : {
|
||||||
|
"r" : 0.3649238,
|
||||||
|
"g" : 0,
|
||||||
|
"b" : 0,
|
||||||
|
"a" : 1
|
||||||
|
},
|
||||||
|
"originalEmissionIntensity" : 0,
|
||||||
|
"attachedElementGuid" : {
|
||||||
|
"value" : "3826be52-7d25-4648-a2fb-a718c01f64c8"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"attachedElementGuid" : {
|
"attachedElementGuid" : {
|
||||||
|
|||||||
@@ -25,10 +25,7 @@
|
|||||||
},
|
},
|
||||||
"parameterName" : "shadowSmoothness"
|
"parameterName" : "shadowSmoothness"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"tempTagMatcherName" : "",
|
|
||||||
"tempElementTypeName" : "",
|
|
||||||
"tempParameterName" : ""
|
|
||||||
},
|
},
|
||||||
"attachedElementGuid" : {
|
"attachedElementGuid" : {
|
||||||
"value" : "00000000-0000-0000-0000-000000000000"
|
"value" : "00000000-0000-0000-0000-000000000000"
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -83,7 +83,8 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse
|
|||||||
|
|
||||||
public override void Adjust()
|
public override void Adjust()
|
||||||
{
|
{
|
||||||
breathParticle?.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
|
if (breathParticle != null)
|
||||||
|
breathParticle.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override EffectBase_BM ConvertToBM()
|
public override EffectBase_BM ConvertToBM()
|
||||||
|
|||||||
@@ -21,8 +21,11 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse
|
|||||||
}
|
}
|
||||||
public override void Recover()
|
public override void Recover()
|
||||||
{
|
{
|
||||||
noteVisual.noteMain.SetActive(true);
|
try
|
||||||
|
{
|
||||||
|
noteVisual.noteMain.SetActive(true);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
if (note is Hold && noteVisual.isHighlighted)
|
if (note is Hold && noteVisual.isHighlighted)
|
||||||
{
|
{
|
||||||
noteVisual.extraPartList[0].gameObject.SetActive(true);
|
noteVisual.extraPartList[0].gameObject.SetActive(true);
|
||||||
@@ -37,7 +40,7 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse
|
|||||||
effectParticle.Play();
|
effectParticle.Play();
|
||||||
|
|
||||||
// effectParticle.transform.DOMove(noteVisual.noteVisualPosition, 0.2f);
|
// effectParticle.transform.DOMove(noteVisual.noteVisualPosition, 0.2f);
|
||||||
|
|
||||||
if (note is Hold && noteVisual.isHighlighted)
|
if (note is Hold && noteVisual.isHighlighted)
|
||||||
{
|
{
|
||||||
noteVisual.extraPartList[0].gameObject.SetActive(false);
|
noteVisual.extraPartList[0].gameObject.SetActive(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user