我死去

This commit is contained in:
2025-11-30 15:13:57 +08:00
parent bcd2c82142
commit d0d373a948
38 changed files with 243029 additions and 16615 deletions

View File

@@ -138,21 +138,29 @@ namespace Ichni.RhythmGame
var z = ((Displacement_BM)displacement.matchedBM).positionZ.DeepCopyBM();
x.ApplyTimeOffset(finalTimeOffset); y.ApplyTimeOffset(finalTimeOffset); z.ApplyTimeOffset(finalTimeOffset);
List<ICanBeTrackedDisplacement> ICanBeTrackedDisplacements = new List<ICanBeTrackedDisplacement> { this as ICanBeTrackedDisplacement };
while (MaybeDeadLoop && ICanBeTrackedDisplacements[0] is not Displacement)
// 构建链表,从底层 Displacement 到最上层 Tracker
List<ICanBeTrackedDisplacement> chain = new List<ICanBeTrackedDisplacement>();
ICanBeTrackedDisplacement cur = this;
int safeGuard = 100; // 防止死循环
while (cur != null && safeGuard-- > 0)
{
ICanBeTrackedDisplacement ao = (ICanBeTrackedDisplacements[0] as DisplacementTracker).targetDisplacement;
ICanBeTrackedDisplacements.Insert(0, ao);
chain.Insert(0, cur);
if (cur is DisplacementTracker tracker)
cur = tracker.targetDisplacement;
else
break;
}
ICanBeTrackedDisplacements.ForEach(o =>
{
((IHaveVector3Interferometer)o).ApplyVector3InterferometersBM(x, y, z);
});
parentElement.SaveBM();
Displacement_BM a = new Displacement_BM("Displacement", elementGuid, new List<string>(), parentElement.matchedBM as GameElement_BM,
x, y, z);
MatchingExportElement = a;
// 依次叠加 Interferometer
foreach (var o in chain)
((IHaveVector3Interferometer)o).ApplyVector3InterferometersBM(x, y, z);
// 先保存 parentElement
parentElement.SaveBM();
// 用当前 elementName/tags
var a = new Displacement_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM, x, y, z);
MatchingExportElement = a;
}
public Displacement GetOriginDisplacementWithOffset(ref float timeOffset)

View File

@@ -1,7 +1,12 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Ichni.Editor;
using Ichni.RhythmGame;
using Ichni.RhythmGame.Beatmap;
using Sirenix.Utilities;
using UnityEngine;
namespace Ichni.RhythmGame
@@ -17,6 +22,7 @@ namespace Ichni.RhythmGame
public string lastSaveTime;
public List<string> selectedThemeBundleList;
public TagManager tagManager;
public string projectPath;
public BaseElement_BM matchedBM { get; set; }
@@ -27,7 +33,7 @@ namespace Ichni.RhythmGame
public string CommandScriptsPath => projectPath + "/CommandScripts.json";
public ProjectInformation(string projectName, string creatorName, string editorVersion,
string createTime, string lastSaveTime, List<string> selectedThemeBundleList)
string createTime, string lastSaveTime, List<string> selectedThemeBundleList, TagManager tagManager = null)
{
this.projectName = projectName;
this.creatorName = creatorName;
@@ -35,7 +41,7 @@ namespace Ichni.RhythmGame
this.createTime = createTime;
this.lastSaveTime = lastSaveTime;
this.selectedThemeBundleList = selectedThemeBundleList;
this.tagManager = tagManager is null ? new() : tagManager;
projectPath = Application.streamingAssetsPath + "/Projects/" + projectName;
EditorManager.instance.uiManager.mainPage.toolBar.projectInfoButton.onClick.AddListener(() =>
{
@@ -47,7 +53,7 @@ namespace Ichni.RhythmGame
public void SaveBM()
{
matchedBM = new ProjectInformation_BM(projectName, creatorName, "0.1.0",
createTime, lastSaveTime, selectedThemeBundleList);
createTime, lastSaveTime, selectedThemeBundleList, tagManager);
}
public void SetUpInspector()
@@ -63,6 +69,7 @@ namespace Ichni.RhythmGame
inspector.GenerateHintText(this, sub, createTime);
inspector.GenerateHintText(this, sub, lastSaveTime);
inspector.GenerateHintText(this, sub, projectPath);
tagManager?.SetUpInspector();
}
}
@@ -76,6 +83,7 @@ namespace Ichni.RhythmGame
public string createTime;
public string lastSaveTime;
public List<string> selectedThemeBundleList;
public TagManager tagManager;
public ProjectInformation_BM()
{
@@ -83,7 +91,7 @@ namespace Ichni.RhythmGame
}
public ProjectInformation_BM(string projectName, string creatorName, string editorVersion,
string createTime, string lastSaveTime, List<string> selectedThemeBundleList)
string createTime, string lastSaveTime, List<string> selectedThemeBundleList, TagManager tagManager = null)
{
this.projectName = projectName;
this.creatorName = creatorName;
@@ -91,13 +99,252 @@ namespace Ichni.RhythmGame
this.createTime = createTime;
this.lastSaveTime = lastSaveTime;
this.selectedThemeBundleList = selectedThemeBundleList;
this.tagManager = tagManager is null ? new() : tagManager;
}
public override void ExecuteBM()
{
EditorManager.instance.projectInformation = new ProjectInformation(projectName,
creatorName, editorVersion, createTime, lastSaveTime, selectedThemeBundleList);
creatorName, editorVersion, createTime, lastSaveTime, selectedThemeBundleList, tagManager);
}
}
}
}
namespace Ichni.Editor
{
public class TagManager : IBaseElement//这玩意大概不需要分BM的
{
public BaseElement_BM matchedBM { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public List<TagMatcher> tagMatchers;
public TagManager()
{
tagMatchers = new List<TagMatcher>();
tempTagMatcherName = "";
tempElementTypeName = "";
tempParameterName = "";
}
public void AddTagMatcher(string name, Type elementType, string parameterName)
{
//check
if (tagMatchers.Any(i => i.name == name))
{
LogWindow.Log("TagMatcher's name is repeated!");
return;
}
tagMatchers.Add(new TagMatcher
{
name = name,
ElementType = elementType,
parameterName = parameterName
});
}
public void AddTagMatcher(TagMatcher o)
{
//check
if (tagMatchers.Any(i => i.name == o.name))
{
LogWindow.Log("TagMatcher's name is repeated!");
return;
}
tagMatchers.Add(o);
}
public void RemoveTagMatcher(TagMatcher o)
{
tagMatchers.Remove(o);
}
public void RemoveTagMatcher(string o)
{
RemoveTagMatcher(tagMatchers.First(i => i.name == o));
}
public List<IBaseElement> GetMachedElements(TagMatcher o)
{
return EditorManager.instance.beatmapContainer.gameElementList
.Where(p => o.Match(p)).Cast<IBaseElement>().ToList();
}
public List<TagMatcher> GetMatcher(GameElement baseElement)
{
return tagMatchers.Where(p => p.Match(baseElement)).ToList();
}
public void SetMatchedElements(TagMatcher o, object value)
{
foreach (var i in GetMachedElements(o))
{
o.SetValue(i, value);
}
}
public void SyncTagedElement(GameElement gameElement)
{
foreach (var matcher in GetMatcher(gameElement))
{
var matchedElements = GetMachedElements(matcher);
foreach (var element in matchedElements)
{
var value = gameElement.GetType().GetField(matcher.parameterName).GetValue(gameElement);
matcher.SetValue(element, value);
element.Refresh();
}
}
}
public string tempTagMatcherName = "";
public string tempElementTypeName = "";
public string tempParameterName = "";
public void SetUpInspector()
{
tempTagMatcherName = "";
tempElementTypeName = "";
tempParameterName = "";
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Tag Manager");
// 展示所有已存在的TagMatcher
for (int i = 0; i < tagMatchers.Count; i++)
{
var matcher = tagMatchers[i];
var sub = container.GenerateSubcontainer(2);
inspector.GenerateHintText(this, sub, $"Name: {matcher.name}");
inspector.GenerateHintText(this, sub, $"Type: {matcher.ElementType?.Name ?? "<null>"}");
inspector.GenerateHintText(this, sub, $"Param: {matcher.parameterName}");
inspector.GenerateButton(this, sub, "Remove", () =>
{
RemoveTagMatcher(matcher);
inspectorMain.SetInspector(EditorManager.instance.projectInformation);
});
}
// 新增TagMatcher区域
var addSub = container.GenerateSubcontainer(3);
// 输入Tag名称
var nameInput = inspector.GenerateInputField(this, addSub, "Tag Name", nameof(tempTagMatcherName));
// 下拉选择类型
List<Type> typeList = TypeHelper.GetInheritedTypes<GameElement>();
List<string> typeNames = typeList.ConvertAll(t => t.FullName);
var typeDropdown = inspector.GenerateDropdown(this, addSub, "Element Type", typeNames, nameof(tempElementTypeName))
.AddListenerFunction(() =>
{
// 选择类型后刷新参数下拉
Type selectedType = typeList.FirstOrDefault(t => t.FullName == tempElementTypeName);
List<string> paramNames = selectedType != null
? selectedType.GetFields().Select(f => f.Name).ToList()
: new List<string>();
//inspector.GenerateDropdown(this, addSub, "Parameter", paramNames, nameof(tempParameterName));
});
// 参数下拉(初始为空,随类型变化刷新)
if (!string.IsNullOrEmpty(tempElementTypeName))
{
Type selectedType = typeList.FirstOrDefault(t => t.FullName == tempElementTypeName);
List<string> paramNames = selectedType != null
? selectedType.GetFields().Select(f => f.Name).ToList()
: new List<string>();
inspector.GenerateDropdown(this, addSub, "Parameter", paramNames, nameof(tempParameterName));
}
else
{
inspector.GenerateDropdown(this, addSub, "Parameter", new List<string>(), nameof(tempParameterName));
}
// 添加按钮
var addButton = inspector.GenerateButton(this, addSub, "Add TagMatcher", () =>
{
if (string.IsNullOrEmpty(tempTagMatcherName) || string.IsNullOrEmpty(tempElementTypeName) || string.IsNullOrEmpty(tempParameterName))
{
Debug.LogWarning("请填写完整信息再添加TagMatcher。");
return;
}
if (tagMatchers.Any(t => t.name == tempTagMatcherName))
{
Debug.LogWarning("TagMatcher's name is repeated!");
return;
}
Type selectedType = typeList.FirstOrDefault(t => t.FullName == tempElementTypeName);
TagMatcher matcher = new TagMatcher
{
name = tempTagMatcherName,
ElementType = selectedType,
parameterName = tempParameterName
};
AddTagMatcher(matcher);
inspectorMain.SetInspector(EditorManager.instance.projectInformation);
});
// 按需禁用添加按钮
if (string.IsNullOrEmpty(tempTagMatcherName) || string.IsNullOrEmpty(tempElementTypeName) || string.IsNullOrEmpty(tempParameterName))
{
addButton.button.interactable = false;
}
}
public struct TagMatcher
{
public string name;
public Type ElementType;
public string parameterName;
public readonly bool Match(GameElement gameElement)
{
string o = name;
return gameElement.tags.Any(i => i == o);
}
public readonly void SetValue(IBaseElement baseElement, object value)
{
if (ElementType != baseElement.GetType()) return;
ElementType.GetField(parameterName).SetValue(baseElement, value);
}
};
}
}
public static class TypeHelper
{
/// <summary>
/// 获取所有继承自指定基类的类型
/// </summary>
public static List<Type> GetInheritedTypes(Type baseType)
{
var result = new List<Type>();
// 遍历当前应用程序域中的所有程序集
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
// 获取程序集中所有类型
var types = assembly.GetTypes()
.Where(t => t.IsClass && !t.IsAbstract && baseType.IsAssignableFrom(t))
.ToList();
result.AddRange(types);
}
catch (ReflectionTypeLoadException)
{
// 忽略无法加载类型的程序集
continue;
}
}
return result;
}
/// <summary>
/// 泛型版本,更方便使用
/// </summary>
public static List<Type> GetInheritedTypes<TBase>()
{
return GetInheritedTypes(typeof(TBase));
}
}