This commit is contained in:
SoulliesOfficial
2026-03-28 06:30:33 -04:00
parent 11423add8f
commit 7533e7031d
20 changed files with 20605 additions and 18964 deletions

View File

@@ -9,6 +9,7 @@ namespace Ichni.RhythmGame.Beatmap
public Track.TrackSamplingType trackSamplingType;
public bool isClosed;
public bool isShowingDisplay;
public int sampleRate = 8;
public TrackPathSubmodule_BM()
{
@@ -23,20 +24,21 @@ namespace Ichni.RhythmGame.Beatmap
this.trackSamplingType = trackPathSubmodule.trackSamplingType;
this.isClosed = trackPathSubmodule.isClosed;
this.isShowingDisplay = trackPathSubmodule.isShowingDisplay;
this.sampleRate = trackPathSubmodule.sampleRate;
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
Track track = attachedElement as Track;
track.trackPathSubmodule = new TrackPathSubmodule(track, trackSpaceType, trackSamplingType, isClosed, isShowingDisplay);
track.trackPathSubmodule = new TrackPathSubmodule(track, trackSpaceType, trackSamplingType, isClosed, isShowingDisplay, sampleRate);
}
#region [Editor ] Editor Interfaces
public override void DuplicateBM(GameElement attached)
{
Track track = attached as Track;
track.trackPathSubmodule = new TrackPathSubmodule(track, trackSpaceType, trackSamplingType, isClosed, isShowingDisplay);
track.trackPathSubmodule = new TrackPathSubmodule(track, trackSpaceType, trackSamplingType, isClosed, isShowingDisplay, sampleRate);
}
#endregion
}

View File

@@ -14,6 +14,11 @@ namespace Ichni.RhythmGame.Beatmap
public bool zWrite; // 新增
public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero;
public string customTextureThemeBundleName = "None";
public string customTextureName = "None";
public Dreamteck.Splines.MeshGenerator.UVMode uvMode = Dreamteck.Splines.MeshGenerator.UVMode.UniformClip;
public float uvRotation = 0f;
public float size = 1f;
public TrackRendererSubmoduleAutoOrient_BM()
{
@@ -30,6 +35,11 @@ namespace Ichni.RhythmGame.Beatmap
zWrite = trackRendererSubmodule.zWrite; // 新增
uvScale = trackRendererSubmodule.uvScale;
uvOffset = trackRendererSubmodule.uvOffset;
customTextureThemeBundleName = trackRendererSubmodule.customTextureThemeBundleName;
customTextureName = trackRendererSubmodule.customTextureName;
uvMode = trackRendererSubmodule.uvMode;
uvRotation = trackRendererSubmodule.uvRotation;
size = trackRendererSubmodule.size;
}
public override void ExecuteBM()
@@ -38,6 +48,11 @@ namespace Ichni.RhythmGame.Beatmap
Track track = attachedElement as Track;
track.trackRendererSubmodule =
new TrackRendererSubmoduleAutoOrient(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
track.trackRendererSubmodule.customTextureThemeBundleName = customTextureThemeBundleName;
track.trackRendererSubmodule.customTextureName = customTextureName;
track.trackRendererSubmodule.uvMode = uvMode;
track.trackRendererSubmodule.uvRotation = uvRotation;
track.trackRendererSubmodule.size = size;
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
@@ -50,6 +65,11 @@ namespace Ichni.RhythmGame.Beatmap
Track track = attached as Track;
track.trackRendererSubmodule =
new TrackRendererSubmoduleAutoOrient(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
track.trackRendererSubmodule.customTextureThemeBundleName = customTextureThemeBundleName;
track.trackRendererSubmodule.customTextureName = customTextureName;
track.trackRendererSubmodule.uvMode = uvMode;
track.trackRendererSubmodule.uvRotation = uvRotation;
track.trackRendererSubmodule.size = size;
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
@@ -68,6 +88,11 @@ namespace Ichni.RhythmGame.Beatmap
public bool zWrite; // 新增
public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero;
public string customTextureThemeBundleName = "None";
public string customTextureName = "None";
public Dreamteck.Splines.MeshGenerator.UVMode uvMode = Dreamteck.Splines.MeshGenerator.UVMode.UniformClip;
public float uvRotation = 90f;
public float size = 1f;
public TrackRendererSubmodulePathGenerator_BM()
{
@@ -84,6 +109,11 @@ namespace Ichni.RhythmGame.Beatmap
zWrite = trackRendererSubmodule.zWrite; // 新增
uvScale = trackRendererSubmodule.uvScale;
uvOffset = trackRendererSubmodule.uvOffset;
customTextureThemeBundleName = trackRendererSubmodule.customTextureThemeBundleName;
customTextureName = trackRendererSubmodule.customTextureName;
uvMode = trackRendererSubmodule.uvMode;
uvRotation = trackRendererSubmodule.uvRotation;
size = trackRendererSubmodule.size;
}
public override void ExecuteBM()
@@ -92,6 +122,11 @@ namespace Ichni.RhythmGame.Beatmap
Track track = attachedElement as Track;
track.trackRendererSubmodule =
new TrackRendererSubmodulePathGenerator(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
track.trackRendererSubmodule.customTextureThemeBundleName = customTextureThemeBundleName;
track.trackRendererSubmodule.customTextureName = customTextureName;
track.trackRendererSubmodule.uvMode = uvMode;
track.trackRendererSubmodule.uvRotation = uvRotation;
track.trackRendererSubmodule.size = size;
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
@@ -104,6 +139,11 @@ namespace Ichni.RhythmGame.Beatmap
Track track = attached as Track;
track.trackRendererSubmodule =
new TrackRendererSubmodulePathGenerator(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
track.trackRendererSubmodule.customTextureThemeBundleName = customTextureThemeBundleName;
track.trackRendererSubmodule.customTextureName = customTextureName;
track.trackRendererSubmodule.uvMode = uvMode;
track.trackRendererSubmodule.uvRotation = uvRotation;
track.trackRendererSubmodule.size = size;
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
@@ -124,6 +164,9 @@ namespace Ichni.RhythmGame.Beatmap
public int sideCount;
public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero;
public Dreamteck.Splines.MeshGenerator.UVMode uvMode = Dreamteck.Splines.MeshGenerator.UVMode.UniformClip;
public float uvRotation = 0f;
public float size = 1f;
public TrackRendererSubmoduleTubeGenerator_BM()
{
@@ -141,6 +184,9 @@ namespace Ichni.RhythmGame.Beatmap
sideCount = trackRendererSubmodule.sideCount;
uvScale = trackRendererSubmodule.uvScale;
uvOffset = trackRendererSubmodule.uvOffset;
uvMode = trackRendererSubmodule.uvMode;
uvRotation = trackRendererSubmodule.uvRotation;
size = trackRendererSubmodule.size;
}
public override void ExecuteBM()
@@ -149,6 +195,9 @@ namespace Ichni.RhythmGame.Beatmap
Track track = attachedElement as Track;
track.trackRendererSubmodule =
new TrackRendererSubmoduleTubeGenerator(track, enableEmission, emissionIntensity, zWrite, sideCount, uvScale, uvOffset);
track.trackRendererSubmodule.uvMode = uvMode;
track.trackRendererSubmodule.uvRotation = uvRotation;
track.trackRendererSubmodule.size = size;
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
@@ -161,6 +210,9 @@ namespace Ichni.RhythmGame.Beatmap
Track track = attached as Track;
track.trackRendererSubmodule =
new TrackRendererSubmoduleTubeGenerator(track, enableEmission, emissionIntensity, zWrite, sideCount, uvScale, uvOffset);
track.trackRendererSubmodule.uvMode = uvMode;
track.trackRendererSubmodule.uvRotation = uvRotation;
track.trackRendererSubmodule.size = size;
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
@@ -179,6 +231,9 @@ namespace Ichni.RhythmGame.Beatmap
public bool zWrite; // 新增
public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero;
public Dreamteck.Splines.MeshGenerator.UVMode uvMode = Dreamteck.Splines.MeshGenerator.UVMode.UniformClip;
public float uvRotation = 0f;
public float size = 1f;
public TrackRendererSubmoduleSurface_BM()
{
@@ -195,6 +250,9 @@ namespace Ichni.RhythmGame.Beatmap
zWrite = trackRendererSubmodule.zWrite; // 新增
uvScale = trackRendererSubmodule.uvScale;
uvOffset = trackRendererSubmodule.uvOffset;
uvMode = trackRendererSubmodule.uvMode;
uvRotation = trackRendererSubmodule.uvRotation;
size = trackRendererSubmodule.size;
}
public override void ExecuteBM()
@@ -203,6 +261,9 @@ namespace Ichni.RhythmGame.Beatmap
Track track = attachedElement as Track;
track.trackRendererSubmodule =
new TrackRendererSubmoduleSurface(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
track.trackRendererSubmodule.uvMode = uvMode;
track.trackRendererSubmodule.uvRotation = uvRotation;
track.trackRendererSubmodule.size = size;
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
@@ -215,6 +276,9 @@ namespace Ichni.RhythmGame.Beatmap
Track track = attached as Track;
track.trackRendererSubmodule =
new TrackRendererSubmoduleSurface(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
track.trackRendererSubmodule.uvMode = uvMode;
track.trackRendererSubmodule.uvRotation = uvRotation;
track.trackRendererSubmodule.size = size;
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);

View File

@@ -63,6 +63,41 @@ namespace Ichni.RhythmGame
this, "", "", false, 0, 1, ParticleSystemSimulationSpace.World,
10, 5, 1, 1, true, Vector3.zero);
});
var generateTools = container.GenerateSubcontainer(1);
inspector.GenerateButton(this, generateTools, "Time Shift Tool", () =>
{
GeneralSecondaryWindow timeShiftWindow = UnityEngine.Object.Instantiate(
EditorManager.instance.basePrefabs.generalSecondaryWindow,
EditorManager.instance.uiManager.WindowsCanvas.GetComponent<RectTransform>())
.GetComponent<GeneralSecondaryWindow>();
timeShiftWindow.Initialize("Time Shift Tool");
var windowContainer = timeShiftWindow.GenerateContainer("Settings");
var subBase = windowContainer.GenerateSubcontainer(3);
var affectNoteToggle = timeShiftWindow.GenerateToggle(subBase, "Affect Notes", true);
var offsetInput = timeShiftWindow.GenerateInputField(subBase, "Time Offset (seconds)", "0");
var btnBase = windowContainer.GenerateSubcontainer(2);
timeShiftWindow.GenerateButton(btnBase, "Apply", () =>
{
if (float.TryParse(offsetInput.inputField.text, out float offset))
{
ApplyTimeShiftRecursive(affectNoteToggle.toggle.isOn, offset);
UnityEngine.Object.Destroy(timeShiftWindow.gameObject);
LogWindow.Log($"Time shifted by {offset}.", Color.green);
}
else
{
LogWindow.Log("Invalid number format!", Color.red);
}
});
timeShiftWindow.GenerateButton(btnBase, "Cancel", () =>
{
UnityEngine.Object.Destroy(timeShiftWindow.gameObject);
});
});
}
#endregion
@@ -86,6 +121,41 @@ namespace Ichni.RhythmGame
return notes;
}
public void ApplyTimeShiftRecursive(bool affectNotes, float offset)
{
ApplyTimeShiftToElement(this, affectNotes, offset);
}
private void ApplyTimeShiftToElement(GameElement element, bool affectNotes, float offset)
{
if (element is AnimationBase anim)
{
anim.ApplyTimeOffset(offset);
anim.Refresh();
}
else if (element is NoteBase note && affectNotes)
{
note.exactJudgeTime += offset;
if (note is Hold hold)
{
hold.holdEndTime += offset;
}
note.UpdateNoteInTrack(EditorManager.instance.songInformation.songTime);
note.AddinNoteManager(false);
note.Refresh();
}
// GameElement 本身具有层级结构,所有的 GameElement 都可能会携带子物体(如 EnvironmentObjectTrack 等等)
if (element.childElementList != null && element.childElementList.Count > 0)
{
foreach (var child in element.childElementList)
{
ApplyTimeShiftToElement(child, affectNotes, offset);
}
}
}
#endregion
}
}

View File

@@ -25,6 +25,9 @@ namespace Ichni.RhythmGame
inspector.GenerateDropdown(this, trackPathSubmoduleSettings, "Space Type", typeof(Track.TrackSpaceType), nameof(trackSpaceType));
var trackSamplingDropdown =
inspector.GenerateDropdown(this, trackPathSubmoduleSettings, "Sampling Type", typeof(Track.TrackSamplingType), nameof(trackSamplingType));
var trackSampleRateInput =
inspector.GenerateInputField(this, trackPathSubmoduleSettings, "Sample Rate", nameof(sampleRate))
.AddListenerFunction(() => { path.sampleRate = sampleRate; Refresh(); });
var isClosedToggle =
inspector.GenerateToggle(this, trackPathSubmoduleSettings, "Is Closed", nameof(isClosed))
.AddListenerFunction(ClosePath);

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
@@ -35,6 +36,14 @@ namespace Ichni.RhythmGame
inspector.GenerateVector2InputField(this, uvSettings, "UV Offset", nameof(uvOffset))
.AddListenerFunction(SetUV);
var meshSettings = container.GenerateSubcontainer(3);
inspector.GenerateDropdown(this, meshSettings, "UV Mode", typeof(Dreamteck.Splines.MeshGenerator.UVMode), nameof(uvMode))
.AddListenerFunction(SetUV);
inspector.GenerateInputField(this, meshSettings, "UV Rotation", nameof(uvRotation))
.AddListenerFunction(SetUV);
inspector.GenerateInputField(this, meshSettings, "Size", nameof(size))
.AddListenerFunction(SetUV);
var materialSettings = container.GenerateSubcontainer(3);
var themeBundleDropdown = inspector
.GenerateDropdown(this, materialSettings, "Theme Bundle", ThemeBundleManager.instance.selectedThemeBundleList, nameof(materialThemeBundleName))
@@ -53,6 +62,33 @@ namespace Ichni.RhythmGame
var applyMaterialButton = inspector.GenerateButton(this, materialSettings, "Apply Material", () => { ApplyMaterial(materialThemeBundleName, materialName); });
var textureSettings = container.GenerateSubcontainer(3);
var textureThemeBundleDropdown = inspector
.GenerateDropdown(this, textureSettings, "Tex Bundle", ThemeBundleManager.instance.selectedThemeBundleList, nameof(customTextureThemeBundleName))
.AddListenerFunction(() => inspectorMain.SetInspector(track));
if (customTextureThemeBundleName != String.Empty && ThemeBundleManager.instance.TryGetThemeBundle(customTextureThemeBundleName, out ThemeBundle texThemeBundle))
{
List<string> texNameList = new List<string>();
texNameList.Add("None");
var textureNames = new List<string>();
if (texThemeBundle.assetList_Texture != null) textureNames.AddRange(texThemeBundle.assetList_Texture.ConvertAll(x => x.name));
if (texThemeBundle.assetList_Other != null) textureNames.AddRange(texThemeBundle.assetList_Other.FindAll(x => x is Sprite).ConvertAll(x => x.name));
// Remove duplicates
texNameList.AddRange(new HashSet<string>(textureNames));
var textureNameDropdown = inspector.GenerateDropdown(this, textureSettings, "Texture Name", texNameList, nameof(customTextureName))
.AddListenerFunction(() => inspectorMain.SetInspector(track));
}
else
{
var textureNameDropdown = inspector.GenerateDropdown(this, textureSettings, "Texture Name", new List<string>() { "None" }, nameof(customTextureName));
textureNameDropdown.dropdown.interactable = false;
}
var applyTextureButton = inspector.GenerateButton(this, textureSettings, "Apply Texture", () => { Refresh(); });
var delete = container.GenerateSubcontainer(3);
var deleteButton = inspector.GenerateButton(this, delete, "Delete", () =>
{
@@ -111,6 +147,9 @@ namespace Ichni.RhythmGame
{
meshGenerator.uvScale = uvScale;
meshGenerator.uvOffset = uvOffset;
meshGenerator.uvRotation = uvRotation;
meshGenerator.uvMode = uvMode;
meshGenerator.size = size;
}
#endregion
}

View File

@@ -13,6 +13,7 @@ namespace Ichni.RhythmGame
public FlexibleReturnType animationReturnType;
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
#endregion
#region [] Initialization
@@ -34,6 +35,11 @@ namespace Ichni.RhythmGame
// 向 AnimationManager 注册,通过中废集权 Update 驱动,替代 MonoBehaviour.Update()
AnimationManager.instance.RegisterAnimation(this);
}
public virtual void OnDirtyRefresh(Dictionary<string, bool> flags)
{
}
public override void OnDelete()
{

View File

@@ -19,11 +19,12 @@ namespace Ichni.RhythmGame
public bool isClosed;
public bool isShowingDisplay;
public int sampleRate = 8;
#endregion
#region [] Initialization
public TrackPathSubmodule(Track track, Track.TrackSpaceType trackSpaceType,
Track.TrackSamplingType trackSamplingType, bool isClosed, bool isShowingDisplay) : base(track)
Track.TrackSamplingType trackSamplingType, bool isClosed, bool isShowingDisplay, int sampleRate = 8) : base(track)
{
this.path = track.AddComponent<SplineComputer>();
@@ -32,7 +33,8 @@ namespace Ichni.RhythmGame
this.trackSamplingType = trackSamplingType;
this.isClosed = isClosed;
this.path.sampleRate = 8;
this.sampleRate = sampleRate;
this.path.sampleRate = sampleRate;
this.path.updateMode = SplineComputer.UpdateMode.LateUpdate;
SetUpSplineComputer(this.trackSpaceType, this.trackSamplingType);
@@ -54,6 +56,7 @@ namespace Ichni.RhythmGame
path.type = (Spline.Type)trackSpaceType;
path.sampleMode = (SplineComputer.SampleMode)(int)trackSamplingType;
path.space = SplineComputer.Space.Local;
path.sampleRate = sampleRate;
}
#endregion

View File

@@ -18,6 +18,11 @@ namespace Ichni.RhythmGame
public string materialThemeBundleName;
public string materialName;
public string customTextureThemeBundleName = "None";
public string customTextureName = "None";
public MeshGenerator.UVMode uvMode = MeshGenerator.UVMode.UniformClip;
public float uvRotation = 0f;
public float size = 1f;
public bool enableEmission;
public float emissionIntensity;
public bool zWrite;
@@ -87,6 +92,23 @@ namespace Ichni.RhythmGame
var block = new MaterialPropertyBlock();
meshRenderer.GetPropertyBlock(block);
if (!string.IsNullOrEmpty(customTextureName) && customTextureName != "None")
{
if (renderMaterial != null && (renderMaterial.name.Contains("DefaultTrackMaterial") || renderMaterial.shader.name == "Soullies/TrackShader" || renderMaterial.shader.name == "TrackShader"))
{
Texture2D tex = ThemeBundleManager.instance.GetObject<Texture2D>(customTextureThemeBundleName, customTextureName);
if (tex == null)
{
Sprite sp = ThemeBundleManager.instance.GetObject<Sprite>(customTextureThemeBundleName, customTextureName);
if (sp != null) tex = sp.texture;
}
if (tex != null)
{
block.SetTexture("_MainTexture", tex);
}
}
}
// ZWrite
block.SetFloat("_ZWrite", zWrite ? 1f : 0f);
@@ -105,6 +127,9 @@ namespace Ichni.RhythmGame
// UV仍然直接设置到 meshGenerator
meshGenerator.uvScale = uvScale;
meshGenerator.uvOffset = uvOffset;
meshGenerator.uvRotation = uvRotation;
meshGenerator.uvMode = uvMode;
meshGenerator.size = size;
meshRenderer.SetPropertyBlock(block);

View File

@@ -34,8 +34,8 @@ namespace Ichni.RhythmGame
this.splineRenderer.updateMethod = SplineUser.UpdateMethod.Update;
this.meshRenderer.material = renderMaterial;
this.splineRenderer.color = Color.white;
this.splineRenderer.uvRotation = 90;
this.splineRenderer.uvMode = MeshGenerator.UVMode.UniformClip;
this.uvRotation = 0f;
this.uvMode = MeshGenerator.UVMode.UniformClip;
this.submoduleNameIndex = 0; // Auto Orient is the first submodule
}

View File

@@ -31,8 +31,8 @@ namespace Ichni.RhythmGame
this.pathGenerator.updateMethod = SplineUser.UpdateMethod.Update;
this.meshRenderer.material = renderMaterial;
this.pathGenerator.color = Color.white;
this.pathGenerator.uvRotation = 90;
this.pathGenerator.uvMode = MeshGenerator.UVMode.UniformClip;
this.uvRotation = 90f;
this.uvMode = MeshGenerator.UVMode.UniformClip;
this.submoduleNameIndex = 1; // Path Generator is the second submodule
}