Export override 修改

Signed-off-by: TRADER_FOER <lhf190@outlook.com>
This commit is contained in:
2026-06-20 11:04:51 +08:00
parent 545bfae0db
commit c7ba1a4c03
19 changed files with 27597 additions and 814 deletions

View File

@@ -25,7 +25,7 @@ using UnityEngine.InputSystem;
namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写符合C#规范
{
public partial class FastNoteTracker : GameElement, IBeChangeInExport
public partial class FastNoteTracker : GameElement
{
public Track TrackedTrack { get => parentElement as Track; }
private bool _isEnabled = false;
@@ -58,8 +58,6 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
}
}
private bool _showNotePreview = false;
BaseElement_BM IBeChangeInExport.MatchingExportElement { get => null; set { } }
// NotePreview和TextHint的容器
private Transform _previewRoot;
private Transform PreviewRoot
@@ -535,10 +533,6 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
// 后面的 Inspector 和 Export 代码逻辑暂时不需要大改,只要注意变量名 Beatdiver -> BeatDiver
public partial class FastNoteTracker
{
public BaseElement_BM MatchingExportElement { get => null; set => throw new System.NotImplementedException(); }
public void SaveExportBM() { }
public override void SetUpInspector()
{
base.SetUpInspector();

View File

@@ -28,6 +28,7 @@ public partial class EventPoint : MonoBehaviour
public TMP_Text ViewText;
public static bool Locked = false;
private UILineRenderer _overflowLine;
public int BeatDeviver => FatherTab.BeatDeviver;
public void Initialize(AnimatedFloat animatedFloat)
{
@@ -63,10 +64,8 @@ public partial class EventPoint : MonoBehaviour
Linerender.rectTransform.pivot = EvDrawimage.rectTransform.pivot;
Linerender.rectTransform.anchoredPosition = EvDrawimage.rectTransform.anchoredPosition;
// 创建/同步溢出红色线条
SyncOverflowLine();
}
public float value => FatherTab.scalevalue;
@@ -234,6 +233,30 @@ public partial class EventPoint : MonoBehaviour
animatedFloat.animationCurveType
);
}
private void SyncOverflowLine()
{
if (Linerender == null) return;
if (_overflowLine == null)
{
GameObject go = new GameObject("OverflowLine", typeof(RectTransform));
go.transform.SetParent(Linerender.transform.parent, false);
_overflowLine = go.AddComponent<UILineRenderer>();
_overflowLine.color = Color.red;
_overflowLine.RelativeSize = true;
_overflowLine.LineThickness = Linerender.LineThickness;
_overflowLine.raycastTarget = false;
}
// 每次同步位置/大小,确保跟随 EventPoint 变化
_overflowLine.rectTransform.anchorMin = Linerender.rectTransform.anchorMin;
_overflowLine.rectTransform.anchorMax = Linerender.rectTransform.anchorMax;
_overflowLine.rectTransform.pivot = Linerender.rectTransform.pivot;
_overflowLine.rectTransform.sizeDelta = Linerender.rectTransform.sizeDelta;
_overflowLine.rectTransform.anchoredPosition = Linerender.rectTransform.anchoredPosition;
}
}
public partial class EventPoint//显示?
{
@@ -244,19 +267,66 @@ public partial class EventPoint//显示?
int width = Mathf.Max(2, (int)Linerender.rectTransform.sizeDelta.x / 5);
int height = Mathf.Max(1, (int)Linerender.rectTransform.sizeDelta.y / 5);
// 使用 UILineRenderer 直接绘制曲线(替代原来的纹理生成
Linerender.RelativeSize = true;
Linerender.color = Color.green;
Vector2[] points = new Vector2[width];
// 计算原始 y 值(未裁剪
float[] rawY = new float[width];
for (int i = 0; i < width; i++)
{
float t = (float)i / (width - 1);
float curveVal = animatedFloat.startValue * value + ((animatedFloat.endValue - animatedFloat.startValue)
* AnimationCurveEvaluator.Evaluate(animatedFloat.animationCurveType, t) * value);
float yNorm = 0.5f + curveVal / height;
points[i] = new Vector2(t, yNorm);
rawY[i] = 0.5f + curveVal / height;
}
// 分割为绿色连续段(框内)和红色连续段(框外Y循环)
var greenSegs = new List<Vector2[]>();
var redSegs = new List<Vector2[]>();
var curGreen = new List<Vector2>();
var curRed = new List<Vector2>();
for (int i = 0; i < width; i++)
{
float t = (float)i / (width - 1);
float y = rawY[i];
bool inBounds = y >= 0f && y <= 1f;
if (inBounds)
{
if (curRed.Count > 0)
{
if (curRed.Count >= 2) redSegs.Add(curRed.ToArray());
curRed.Clear();
}
curGreen.Add(new Vector2(t, y));
}
else
{
if (curGreen.Count > 0)
{
if (curGreen.Count >= 2) greenSegs.Add(curGreen.ToArray());
curGreen.Clear();
}
// Y 循环回框内
float wrappedY = y;
while (wrappedY < 0f) wrappedY += 1f;
while (wrappedY > 1f) wrappedY -= 1f;
curRed.Add(new Vector2(t, wrappedY));
}
}
if (curGreen.Count >= 2) greenSegs.Add(curGreen.ToArray());
if (curRed.Count >= 2) redSegs.Add(curRed.ToArray());
// 设置绿色主线和红色溢出线
Linerender.RelativeSize = true;
Linerender.color = Color.green;
Linerender.Segments = greenSegs.Count > 0 ? greenSegs : null;
if (_overflowLine != null)
{
_overflowLine.RelativeSize = true;
_overflowLine.color = Color.red;
_overflowLine.Segments = redSegs.Count > 0 ? redSegs : null;
}
Linerender.Points = points;
// 其余的非纹理相关代码保持不变
if (NextEventPoint != null)

View File

@@ -38,34 +38,35 @@ namespace Ichni.RhythmGame.Beatmap
e.SaveBM();
e.submoduleList.RemoveAll(s => s == null);
e.submoduleList.ForEach(s => s.SaveBM());
if (forExport && e is IBeChangeInExport changeInExport)
{
changeInExport.SaveExportBM();
}
});
foreach (var gameElement in gameElementList)
{
if (gameElement.matchedBM == null) continue;
if (forExport && gameElement is IBeChangeInExport changeInExport)
BaseElement_BM elementToAdd = gameElement.matchedBM;
// 检查是否有导出替换元素,有则使用替代元素
if (forExport && gameElement is IExportOverride exportOverride)
{
if (changeInExport.MatchingExportElement != null)
BaseElement_BM exportElement = exportOverride.GetExportElement();
if (exportElement != null)
{
elementList.Add(changeInExport.MatchingExportElement);
List<BaseElement_BM> submodules = gameElement.submoduleList.ConvertAll(s => s.matchedBM);
submodules.RemoveAll(s => s == null);
submodules.ForEach(e => { e.attachedElementGuid = ((GameElement_BM)changeInExport.MatchingExportElement).elementGuid; });
elementList.AddRange(submodules);
elementToAdd = exportElement;
}
}
else
elementList.Add(elementToAdd);
List<BaseElement_BM> submodules = gameElement.submoduleList.ConvertAll(s => s.matchedBM);
submodules.RemoveAll(s => s == null);
// 当使用了替代元素时,将其 Guid 附给子模块
if (elementToAdd != gameElement.matchedBM)
{
elementList.Add(gameElement.matchedBM);
List<BaseElement_BM> submodules = gameElement.submoduleList.ConvertAll(s => s.matchedBM);
submodules.RemoveAll(s => s == null);
elementList.AddRange(submodules);
submodules.ForEach(s => { s.attachedElementGuid = ((GameElement_BM)elementToAdd).elementGuid; });
}
elementList.AddRange(submodules);
}
}
#endregion

View File

@@ -13,27 +13,22 @@ namespace Ichni.RhythmGame
Override
}
public abstract class InterferometerBase : GameElement, IHaveTimeDurationSubmodule, IBeChangeInExport
public abstract class InterferometerBase : GameElement, IHaveTimeDurationSubmodule
{
#region [] Property Caches
public AnimationBase parentAnimationElement;
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
public BaseElement_BM MatchingExportElement { get; set; }
public InterferomType InterferomType;
#endregion
#region [] Export Interface
public virtual void SaveExportBM()
{
MatchingExportElement = null;
}
#endregion
}
public interface IBeChangeInExport
/// <summary>
/// 提供导出时替换当前元素的替代 BM 元素。返回 null 表示不需要替换,使用默认逻辑。
/// 实现方在 GetExportElement() 中完成准备工作SaveBM、干涉仪、烘焙然后返回替代元素。
/// </summary>
public interface IExportOverride
{
public BaseElement_BM MatchingExportElement { get; set; }
void SaveExportBM();
BaseElement_BM GetExportElement();
}
public interface IHaveInterferometer

View File

@@ -6,7 +6,7 @@ using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class DisplacementTracker : AnimationBase, IBeChangeInExport, IHaveVector3Interferometer, IHaveTimeDurationSubmodule, ICanBeTrackedDisplacement
public partial class DisplacementTracker : AnimationBase, IExportOverride, IHaveVector3Interferometer, IHaveTimeDurationSubmodule, ICanBeTrackedDisplacement
{
#region [] Property Caches
private TransformSubmodule targetTransformSubmodule;
@@ -14,7 +14,7 @@ namespace Ichni.RhythmGame
private FlexibleFloat positionX, positionY, positionZ;
public Vector3 PreviewValue = Vector3.zero;
public float TimeOffset;
public BaseElement_BM MatchingExportElement { get; set; } = null;
public bool MaybeDeadLoop = true;
public List<InterferometerBase> Interferometers { get; set; } = new();
#endregion
@@ -159,9 +159,9 @@ namespace Ichni.RhythmGame
public override Vector3 getValue(float time)
{
Vector3 currentPosition = new Vector3(
positionX.GetValue(time + TimeOffset),
positionY.GetValue(time + TimeOffset),
positionZ.GetValue(time + TimeOffset)
positionX.GetValue(time),
positionY.GetValue(time),
positionZ.GetValue(time)
);
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentPosition);
return currentPosition;
@@ -169,12 +169,15 @@ namespace Ichni.RhythmGame
public Displacement GetOriginDisplacementWithOffset(ref float timeOffset)
{
return null;
timeOffset += TimeOffset;
if (targetDisplacement is Displacement disp) return disp;
else if (targetDisplacement is DisplacementTracker dispTracker) return dispTracker.GetOriginDisplacementWithOffset(ref timeOffset);
else throw new Exception("WTF type of tracked displacement.");
}
public (FlexibleReturnType, bool)[] GetCurrentReturnTypes(float time)
{
throw new NotImplementedException();
return targetDisplacement.GetCurrentReturnTypes(time + TimeOffset);
}
#endregion
@@ -185,15 +188,13 @@ namespace Ichni.RhythmGame
((GameElement)targetDisplacement).elementGuid, TimeOffset);
}
public void SaveExportBM()
public BaseElement_BM GetExportElement()
{
Refresh();
SaveBM();
MatchingExportElement = matchedBM;
parentElement.SaveBM();
var a = new Displacement_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
return new Displacement_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
positionX.ConvertToBM(), positionY.ConvertToBM(), positionZ.ConvertToBM());
MatchingExportElement = a;
}
#endregion

View File

@@ -6,7 +6,7 @@ using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class ScaleTracker : AnimationBase, IBeChangeInExport, IHaveVector3Interferometer, IHaveTimeDurationSubmodule, ICanBeTrackedScale
public partial class ScaleTracker : AnimationBase, IExportOverride, IHaveVector3Interferometer, IHaveTimeDurationSubmodule, ICanBeTrackedScale
{
#region [] Property Caches
private TransformSubmodule targetTransformSubmodule;
@@ -14,7 +14,6 @@ namespace Ichni.RhythmGame
public Vector3 PreviewValue = Vector3.zero;
public float TimeOffset;
public bool MaybeDeadLoop = true;
public BaseElement_BM MatchingExportElement { get; set; } = null;
public List<InterferometerBase> Interferometers { get; set; } = new();
private FlexibleFloat scaleX, scaleY, scaleZ;
#endregion
@@ -147,15 +146,18 @@ namespace Ichni.RhythmGame
public (FlexibleReturnType, bool)[] GetCurrentReturnTypes(float time)
{
return targetScale.GetCurrentReturnTypes(time + TimeOffset);
(FlexibleReturnType, bool) x = scaleX.getReturnType(time);
(FlexibleReturnType, bool) y = scaleY.getReturnType(time);
(FlexibleReturnType, bool) z = scaleZ.getReturnType(time);
return new (FlexibleReturnType, bool)[] { x, y, z };
}
public override Vector3 getValue(float time)
{
Vector3 currentScale = new Vector3(
scaleX.GetValue(time + TimeOffset),
scaleY.GetValue(time + TimeOffset),
scaleZ.GetValue(time + TimeOffset)
scaleX.GetValue(time),
scaleY.GetValue(time),
scaleZ.GetValue(time)
);
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentScale);
return currentScale;
@@ -177,15 +179,13 @@ namespace Ichni.RhythmGame
((GameElement)targetScale).elementGuid, TimeOffset);
}
public void SaveExportBM()
public BaseElement_BM GetExportElement()
{
Refresh();
SaveBM();
MatchingExportElement = matchedBM;
parentElement.SaveBM();
var a = new Scale_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
return new Scale_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
scaleX.ConvertToBM(), scaleY.ConvertToBM(), scaleZ.ConvertToBM());
MatchingExportElement = a;
}
#endregion
}

View File

@@ -6,7 +6,7 @@ using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class SwirlTracker : AnimationBase, IBeChangeInExport, IHaveVector3Interferometer, IHaveTimeDurationSubmodule, ICanBeTrackedSwirl
public partial class SwirlTracker : AnimationBase, IExportOverride, IHaveVector3Interferometer, IHaveTimeDurationSubmodule, ICanBeTrackedSwirl
{
#region [] Property Caches
private TransformSubmodule targetTransformSubmodule;
@@ -14,7 +14,6 @@ namespace Ichni.RhythmGame
public Vector3 PreviewValue = Vector3.zero;
public float TimeOffset;
public bool MaybeDeadLoop = true;
public BaseElement_BM MatchingExportElement { get; set; } = null;
public List<InterferometerBase> Interferometers { get; set; } = new();
private FlexibleFloat eulerAngleX, eulerAngleY, eulerAngleZ;
#endregion
@@ -147,15 +146,18 @@ namespace Ichni.RhythmGame
public (FlexibleReturnType, bool)[] GetCurrentReturnTypes(float time)
{
return targetSwirl.GetCurrentReturnTypes(time + TimeOffset);
(FlexibleReturnType, bool) x = eulerAngleX.getReturnType(time);
(FlexibleReturnType, bool) y = eulerAngleY.getReturnType(time);
(FlexibleReturnType, bool) z = eulerAngleZ.getReturnType(time);
return new (FlexibleReturnType, bool)[] { x, y, z };
}
public override Vector3 getValue(float time)
{
Vector3 currentEulerAngles = new Vector3(
eulerAngleX.GetValue(time + TimeOffset),
eulerAngleY.GetValue(time + TimeOffset),
eulerAngleZ.GetValue(time + TimeOffset)
eulerAngleX.GetValue(time),
eulerAngleY.GetValue(time),
eulerAngleZ.GetValue(time)
);
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentEulerAngles);
return currentEulerAngles;
@@ -177,15 +179,13 @@ namespace Ichni.RhythmGame
((GameElement)targetSwirl).elementGuid, TimeOffset);
}
public void SaveExportBM()
public BaseElement_BM GetExportElement()
{
Refresh();
SaveBM();
MatchingExportElement = matchedBM;
parentElement.SaveBM();
var a = new Swirl_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
return new Swirl_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
eulerAngleX.ConvertToBM(), eulerAngleY.ConvertToBM(), eulerAngleZ.ConvertToBM());
MatchingExportElement = a;
}
#endregion
}

View File

@@ -7,14 +7,13 @@ using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class Displacement : AnimationBase, IHaveVector3Interferometer, ICanBeTrackedDisplacement
public partial class Displacement : AnimationBase, IHaveVector3Interferometer, IExportOverride, ICanBeTrackedDisplacement
{
#region [] Property Caches
private TransformSubmodule targetTransformSubmodule;
public FlexibleFloat positionX, positionY, positionZ;
public List<InterferometerBase> Interferometers { get; set; } = new List<InterferometerBase>();
public Vector3 PreviewValue = Vector3.zero;
public BaseElement_BM MatchingExportElement { get; set; }
#endregion
#region [] Generation & Initialization
@@ -113,14 +112,14 @@ namespace Ichni.RhythmGame
positionX.ConvertToBM(), positionY.ConvertToBM(), positionZ.ConvertToBM());
}
public void SaveExportBM()
public BaseElement_BM GetExportElement()
{
SaveBM();
MatchingExportElement = matchedBM;
((IHaveVector3Interferometer)this).ApplyVector3InterferometersBM(
(MatchingExportElement as Displacement_BM).positionX,
(MatchingExportElement as Displacement_BM).positionY,
(MatchingExportElement as Displacement_BM).positionZ);
(matchedBM as Displacement_BM).positionX,
(matchedBM as Displacement_BM).positionY,
(matchedBM as Displacement_BM).positionZ);
return matchedBM;
}
#endregion
}

View File

@@ -6,13 +6,12 @@ using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class Scale : AnimationBase, IHaveVector3Interferometer, IBeChangeInExport, ICanBeTrackedScale
public partial class Scale : AnimationBase, IHaveVector3Interferometer, IExportOverride, ICanBeTrackedScale
{
#region [] Property Caches
public TransformSubmodule targetTransformSubmodule;
public FlexibleFloat scaleX, scaleY, scaleZ;
public List<InterferometerBase> Interferometers { get; set; } = new List<InterferometerBase>();
public BaseElement_BM MatchingExportElement { get; set; }
public Vector3 PreviewValue = Vector3.zero;
#endregion
@@ -134,14 +133,14 @@ namespace Ichni.RhythmGame
scaleX.ConvertToBM(), scaleY.ConvertToBM(), scaleZ.ConvertToBM());
}
public void SaveExportBM()
public BaseElement_BM GetExportElement()
{
SaveBM();
MatchingExportElement = matchedBM;
((IHaveVector3Interferometer)this).ApplyVector3InterferometersBM(
(MatchingExportElement as Scale_BM).scaleX,
(MatchingExportElement as Scale_BM).scaleY,
(MatchingExportElement as Scale_BM).scaleZ);
(matchedBM as Scale_BM).scaleX,
(matchedBM as Scale_BM).scaleY,
(matchedBM as Scale_BM).scaleZ);
return matchedBM;
}
#endregion
}

View File

@@ -6,14 +6,13 @@ using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class Swirl : AnimationBase, IHaveVector3Interferometer, IBeChangeInExport, ICanBeTrackedSwirl
public partial class Swirl : AnimationBase, IHaveVector3Interferometer, IExportOverride, ICanBeTrackedSwirl
{
#region [] Property Caches
private TransformSubmodule targetTransformSubmodule;
public FlexibleFloat eulerAngleX, eulerAngleY, eulerAngleZ;
public List<InterferometerBase> Interferometers { get; set; } = new List<InterferometerBase>();
public Vector3 PreviewValue = Vector3.zero;
public BaseElement_BM MatchingExportElement { get; set; }
#endregion
#region [] Generation & Initialization
@@ -129,14 +128,14 @@ namespace Ichni.RhythmGame
eulerAngleX.ConvertToBM(), eulerAngleY.ConvertToBM(), eulerAngleZ.ConvertToBM());
}
public void SaveExportBM()
public BaseElement_BM GetExportElement()
{
SaveBM();
MatchingExportElement = matchedBM;
((IHaveVector3Interferometer)this).ApplyVector3InterferometersBM(
(MatchingExportElement as Swirl_BM).eulerAngleX,
(MatchingExportElement as Swirl_BM).eulerAngleY,
(MatchingExportElement as Swirl_BM).eulerAngleZ);
(matchedBM as Swirl_BM).eulerAngleX,
(matchedBM as Swirl_BM).eulerAngleY,
(matchedBM as Swirl_BM).eulerAngleZ);
return matchedBM;
}
#endregion
}

View File

@@ -9,7 +9,7 @@ using UnityEngine.Events;
namespace Ichni.RhythmGame
{
public class BeatmapContainer : IBaseElement, IBeChangeInExport
public class BeatmapContainer : IBaseElement, IExportOverride
{
#region [] Property Caches
public List<GameElement> gameElementList;
@@ -18,7 +18,6 @@ namespace Ichni.RhythmGame
public List<UnityAction> lowPriorityActions;
public BaseElement_BM matchedBM { get; set; }
public BaseElement_BM MatchingExportElement { get; set; }
#endregion
#region [] Generation & Initialization
@@ -76,13 +75,14 @@ namespace Ichni.RhythmGame
matchedBM = new BeatmapContainer_BM(gameElementList);
}
public void SaveExportBM()
public BaseElement_BM GetExportElement()
{
MatchingExportElement = new BeatmapContainer_BM(gameElementList, true);
if (((BeatmapContainer_BM)MatchingExportElement).elementList.Any(i => i is ICanNotInExport))
var export = new BeatmapContainer_BM(gameElementList, true);
if (export.elementList.Any(i => i is ICanNotInExport))
{
Debug.LogError("Export Error!");
}
return export;
}
#endregion
}

View File

@@ -96,8 +96,8 @@ namespace Ichni
private void ExportBeatMap(string exportPath)
{
EditorManager.instance.beatmapContainer.SaveExportBM();
ES3.Save("Beatmap", EditorManager.instance.beatmapContainer.MatchingExportElement as BeatmapContainer_BM,
var exportBM = EditorManager.instance.beatmapContainer.GetExportElement();
ES3.Save("Beatmap", exportBM as BeatmapContainer_BM,
exportPath, ProjectManager.ExportSettings);
}