Clean separation between track data and config overrides
In debug builds Config keeps a reference to the last set original track instance from which it can load original values.
This commit is contained in:
		
							parent
							
								
									525c0e108f
								
							
						
					
					
						commit
						d4d3e15de3
					
				|  | @ -917,7 +917,32 @@ namespace MuzikaGromche | ||||||
| 
 | 
 | ||||||
|         public Palette Palette { get; } |         public Palette Palette { get; } | ||||||
|     } |     } | ||||||
|   | 
 | ||||||
|  |     // A proxy audio track with default implementation for every IAudioTrack method that simply forwards requests to the inner IAudioTrack. | ||||||
|  |     public abstract class ProxyAudioTrack(IAudioTrack track) : IAudioTrack | ||||||
|  |     { | ||||||
|  |         internal IAudioTrack Track = track; | ||||||
|  |         string IAudioTrack.Name => Track.Name; | ||||||
|  |         float IAudioTrack.WindUpTimer => Track.WindUpTimer; | ||||||
|  |         int IAudioTrack.Beats => Track.Beats; | ||||||
|  |         int IAudioTrack.LoopOffset => Track.LoopOffset; | ||||||
|  |         AudioType IAudioTrack.AudioType => Track.AudioType; | ||||||
|  |         AudioClip IAudioTrack.LoadedIntro { get => Track.LoadedIntro; set => Track.LoadedIntro = value; } | ||||||
|  |         AudioClip IAudioTrack.LoadedLoop { get => Track.LoadedLoop; set => Track.LoadedLoop = value; } | ||||||
|  |         string IAudioTrack.FileNameIntro => Track.FileNameIntro; | ||||||
|  |         string IAudioTrack.FileNameLoop => Track.FileNameLoop; | ||||||
|  |         float IAudioTrack.BeatsOffset => Track.BeatsOffset; | ||||||
|  |         float IAudioTrack.FadeOutBeat => Track.FadeOutBeat; | ||||||
|  |         float IAudioTrack.FadeOutDuration => Track.FadeOutDuration; | ||||||
|  |         float IAudioTrack.ColorTransitionIn => Track.ColorTransitionIn; | ||||||
|  |         float IAudioTrack.ColorTransitionOut => Track.ColorTransitionOut; | ||||||
|  |         Easing IAudioTrack.ColorTransitionEasing => Track.ColorTransitionEasing; | ||||||
|  |         float[] IAudioTrack.FlickerLightsTimeSeries => Track.FlickerLightsTimeSeries; | ||||||
|  |         float[] IAudioTrack.LyricsTimeSeries => Track.LyricsTimeSeries; | ||||||
|  |         string[] IAudioTrack.LyricsLines => Track.LyricsLines; | ||||||
|  |         Palette IAudioTrack.Palette => Track.Palette; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     // Core audio track implementation with some defaults and config overrides. |     // Core audio track implementation with some defaults and config overrides. | ||||||
|     // Suitable to declare elemnents of SelectableTracksGroup and as a base for standalone selectable tracks. |     // Suitable to declare elemnents of SelectableTracksGroup and as a base for standalone selectable tracks. | ||||||
|     public class CoreAudioTrack : IAudioTrack |     public class CoreAudioTrack : IAudioTrack | ||||||
|  | @ -951,56 +976,17 @@ namespace MuzikaGromche | ||||||
|             init => FileNameLoopOverride = value; |             init => FileNameLoopOverride = value; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public float _BeatsOffset = 0f; |         public float BeatsOffset { get; init; } = 0f; | ||||||
|         public float BeatsOffset |         public float FadeOutBeat { get; init; } = float.NaN; | ||||||
|         { |         public float FadeOutDuration { get; init; } = 2f; | ||||||
|             get => Config.BeatsOffsetOverride ?? _BeatsOffset; |         public float ColorTransitionIn { get; init; } = 0.25f; | ||||||
|             init => _BeatsOffset = value; |         public float ColorTransitionOut { get; init; } = 0.25f; | ||||||
|         } |         public Easing ColorTransitionEasing { get; init; } = Easing.OutExpo; | ||||||
| 
 |  | ||||||
|         public float _FadeOutBeat = float.NaN; |  | ||||||
|         public float FadeOutBeat |  | ||||||
|         { |  | ||||||
|             get => Config.FadeOutBeatOverride ?? _FadeOutBeat; |  | ||||||
|             init => _FadeOutBeat = value; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public float _FadeOutDuration = 2f; |  | ||||||
|         public float FadeOutDuration |  | ||||||
|         { |  | ||||||
|             get => Config.FadeOutDurationOverride ?? _FadeOutDuration; |  | ||||||
|             init => _FadeOutDuration = value; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Duration of color transition, measured in beats. |  | ||||||
|         public float _ColorTransitionIn = 0.25f; |  | ||||||
|         public float ColorTransitionIn |  | ||||||
|         { |  | ||||||
|             get => Config.ColorTransitionInOverride ?? _ColorTransitionIn; |  | ||||||
|             init => _ColorTransitionIn = value; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public float _ColorTransitionOut = 0.25f; |  | ||||||
|         public float ColorTransitionOut |  | ||||||
|         { |  | ||||||
|             get => Config.ColorTransitionOutOverride ?? _ColorTransitionOut; |  | ||||||
|             init => _ColorTransitionOut = value; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Easing function for color transitions. |  | ||||||
|         public Easing _ColorTransitionEasing = Easing.OutExpo; |  | ||||||
|         public Easing ColorTransitionEasing |  | ||||||
|         { |  | ||||||
|             get => Config.ColorTransitionEasingOverride != null |  | ||||||
|                 ? Easing.FindByName(Config.ColorTransitionEasingOverride) |  | ||||||
|                 : _ColorTransitionEasing; |  | ||||||
|             init => _ColorTransitionEasing = value; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         public float[] _FlickerLightsTimeSeries = []; |         public float[] _FlickerLightsTimeSeries = []; | ||||||
|         public float[] FlickerLightsTimeSeries |         public float[] FlickerLightsTimeSeries | ||||||
|         { |         { | ||||||
|             get => Config.FlickerLightsTimeSeriesOverride ?? _FlickerLightsTimeSeries; |             get => _FlickerLightsTimeSeries; | ||||||
|             init |             init | ||||||
|             { |             { | ||||||
|                 Array.Sort(value); |                 Array.Sort(value); | ||||||
|  | @ -1008,12 +994,7 @@ namespace MuzikaGromche | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public float[] _LyricsTimeSeries = []; |         public float[] LyricsTimeSeries { get; private set; } = []; | ||||||
|         public float[] LyricsTimeSeries |  | ||||||
|         { |  | ||||||
|             get => Config.LyricsTimeSeriesOverride ?? _LyricsTimeSeries; |  | ||||||
|             private set => _LyricsTimeSeries = value; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         // Lyrics line may contain multiple tab-separated alternatives. |         // Lyrics line may contain multiple tab-separated alternatives. | ||||||
|         // In such case, a random number chosen and updated once per loop |         // In such case, a random number chosen and updated once per loop | ||||||
|  | @ -1034,12 +1015,7 @@ namespace MuzikaGromche | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public Palette _Palette = Palette.DEFAULT; |         public Palette Palette { get; set; } = Palette.DEFAULT; | ||||||
|         public Palette Palette |  | ||||||
|         { |  | ||||||
|             get => Config.PaletteOverride ?? _Palette; |  | ||||||
|             set => _Palette = value; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Standalone, top-level, selectable audio track |     // Standalone, top-level, selectable audio track | ||||||
|  | @ -1853,9 +1829,6 @@ namespace MuzikaGromche | ||||||
|         : SyncedConfig2<Config> |         : SyncedConfig2<Config> | ||||||
| #endif | #endif | ||||||
|     { |     { | ||||||
|         // Latest set track, used for loading palette and timings. |  | ||||||
|         public static IAudioTrack? CurrentTrack { get; internal set; } = null; |  | ||||||
| 
 |  | ||||||
|         public static ConfigEntry<bool> DisplayLyrics { get; private set; } = null!; |         public static ConfigEntry<bool> DisplayLyrics { get; private set; } = null!; | ||||||
| 
 | 
 | ||||||
|         public static ConfigEntry<float> AudioOffset { get; private set; } = null!; |         public static ConfigEntry<float> AudioOffset { get; private set; } = null!; | ||||||
|  | @ -1867,16 +1840,45 @@ namespace MuzikaGromche | ||||||
|         public static bool ExtrapolateTime { get; private set; } = true; |         public static bool ExtrapolateTime { get; private set; } = true; | ||||||
|         public static bool ShouldSkipWindingPhase { get; private set; } = false; |         public static bool ShouldSkipWindingPhase { get; private set; } = false; | ||||||
| 
 | 
 | ||||||
|         public static Palette? PaletteOverride { get; private set; } = null; | #if DEBUG | ||||||
|  |         // Latest set track, used for loading palette and timings. | ||||||
|  |         private static IAudioTrack? CurrentTrack = null; | ||||||
|  |         // All per-track values that can be overridden | ||||||
|  |         private static float? BeatsOffsetOverride = null; | ||||||
|  |         private static float? FadeOutBeatOverride = null; | ||||||
|  |         private static float? FadeOutDurationOverride = null; | ||||||
|  |         private static float? ColorTransitionInOverride = null; | ||||||
|  |         private static float? ColorTransitionOutOverride = null; | ||||||
|  |         private static string? ColorTransitionEasingOverride = null; | ||||||
|  |         private static float[]? FlickerLightsTimeSeriesOverride = null; | ||||||
|  |         private static float[]? LyricsTimeSeriesOverride = null; | ||||||
|  |         private static Palette? PaletteOverride = null; | ||||||
| 
 | 
 | ||||||
|         public static float? FadeOutBeatOverride { get; private set; } = null; |         private class AudioTrackWithConfigOverride(IAudioTrack track) : ProxyAudioTrack(track), IAudioTrack | ||||||
|         public static float? FadeOutDurationOverride { get; private set; } = null; |         { | ||||||
|         public static float[]? FlickerLightsTimeSeriesOverride { get; private set; } = null; |             float IAudioTrack.BeatsOffset => BeatsOffsetOverride ?? Track.BeatsOffset; | ||||||
|         public static float[]? LyricsTimeSeriesOverride { get; private set; } = null; | 
 | ||||||
|         public static float? BeatsOffsetOverride { get; private set; } = null; |             float IAudioTrack.FadeOutBeat => FadeOutBeatOverride ?? Track.FadeOutBeat; | ||||||
|         public static float? ColorTransitionInOverride { get; private set; } = null; | 
 | ||||||
|         public static float? ColorTransitionOutOverride { get; private set; } = null; |             float IAudioTrack.FadeOutDuration => FadeOutDurationOverride ?? Track.FadeOutDuration; | ||||||
|         public static string? ColorTransitionEasingOverride { get; private set; } = null; | 
 | ||||||
|  |             float IAudioTrack.ColorTransitionIn => ColorTransitionInOverride ?? Track.ColorTransitionIn; | ||||||
|  | 
 | ||||||
|  |             float IAudioTrack.ColorTransitionOut => ColorTransitionOutOverride ?? Track.ColorTransitionOut; | ||||||
|  | 
 | ||||||
|  |             Easing IAudioTrack.ColorTransitionEasing => | ||||||
|  |                 ColorTransitionEasingOverride != null | ||||||
|  |                     ? Easing.FindByName(ColorTransitionEasingOverride) | ||||||
|  |                     : Track.ColorTransitionEasing; | ||||||
|  | 
 | ||||||
|  |             float[] IAudioTrack.FlickerLightsTimeSeries => | ||||||
|  |                 FlickerLightsTimeSeriesOverride ?? Track.FlickerLightsTimeSeries; | ||||||
|  | 
 | ||||||
|  |             float[] IAudioTrack.LyricsTimeSeries => LyricsTimeSeriesOverride ?? Track.LyricsTimeSeries; | ||||||
|  | 
 | ||||||
|  |             Palette IAudioTrack.Palette => PaletteOverride ?? Track.Palette; | ||||||
|  |         } | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|         internal Config(ConfigFile configFile) |         internal Config(ConfigFile configFile) | ||||||
| #if DEBUG | #if DEBUG | ||||||
|  | @ -1955,6 +1957,16 @@ namespace MuzikaGromche | ||||||
| #endif | #endif | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         internal static IAudioTrack OverrideCurrentTrack(IAudioTrack track) | ||||||
|  |         { | ||||||
|  | #if DEBUG | ||||||
|  |             CurrentTrack = track; | ||||||
|  |             return new AudioTrackWithConfigOverride(track); | ||||||
|  | #else | ||||||
|  |             return track; | ||||||
|  | #endif | ||||||
|  |         } | ||||||
|  | 
 | ||||||
| #if DEBUG | #if DEBUG | ||||||
|         // HACK because CSync doesn't provide an API to register a list of config entries |         // HACK because CSync doesn't provide an API to register a list of config entries | ||||||
|         // See https://github.com/lc-sigurd/CSync/issues/11 |         // See https://github.com/lc-sigurd/CSync/issues/11 | ||||||
|  | @ -2068,7 +2080,7 @@ namespace MuzikaGromche | ||||||
| 
 | 
 | ||||||
|             void load() |             void load() | ||||||
|             { |             { | ||||||
|                 var palette = (CurrentTrack as CoreAudioTrack)?._Palette ?? Palette.DEFAULT; |                 var palette = CurrentTrack?.Palette ?? Palette.DEFAULT; | ||||||
|                 var colors = palette.Colors; |                 var colors = palette.Colors; | ||||||
|                 var count = Math.Min(colors.Count(), maxCustomPaletteSize); |                 var count = Math.Min(colors.Count(), maxCustomPaletteSize); | ||||||
| 
 | 
 | ||||||
|  | @ -2101,7 +2113,7 @@ namespace MuzikaGromche | ||||||
|             const string section = "Timings"; |             const string section = "Timings"; | ||||||
|             var colorTransitionRange = new AcceptableValueRange<float>(0f, 1f); |             var colorTransitionRange = new AcceptableValueRange<float>(0f, 1f); | ||||||
|             // Declare and initialize early to avoid "Use of unassigned local variable" |             // Declare and initialize early to avoid "Use of unassigned local variable" | ||||||
|             List<(Action<CoreAudioTrack?> Load, Action Apply)> entries = []; |             List<(Action<IAudioTrack?> Load, Action Apply)> entries = []; | ||||||
|             SyncedEntry<bool> overrideTimingsSyncedEntry = null!; |             SyncedEntry<bool> overrideTimingsSyncedEntry = null!; | ||||||
|             SyncedEntry<float> fadeOutBeatSyncedEntry = null!; |             SyncedEntry<float> fadeOutBeatSyncedEntry = null!; | ||||||
|             SyncedEntry<float> fadeOutDurationSyncedEntry = null!; |             SyncedEntry<float> fadeOutDurationSyncedEntry = null!; | ||||||
|  | @ -2151,21 +2163,21 @@ namespace MuzikaGromche | ||||||
|             LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(colorTransitionOutSyncedEntry.Entry, floatSliderOptions)); |             LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(colorTransitionOutSyncedEntry.Entry, floatSliderOptions)); | ||||||
|             LethalConfigManager.AddConfigItem(new TextDropDownConfigItem(colorTransitionEasingSyncedEntry.Entry, Default(new TextDropDownOptions()))); |             LethalConfigManager.AddConfigItem(new TextDropDownConfigItem(colorTransitionEasingSyncedEntry.Entry, Default(new TextDropDownOptions()))); | ||||||
| 
 | 
 | ||||||
|             registerStruct(fadeOutBeatSyncedEntry, t => t._FadeOutBeat, x => FadeOutBeatOverride = x); |             registerStruct(fadeOutBeatSyncedEntry, t => t.FadeOutBeat, x => FadeOutBeatOverride = x); | ||||||
|             registerStruct(fadeOutDurationSyncedEntry, t => t._FadeOutDuration, x => FadeOutDurationOverride = x); |             registerStruct(fadeOutDurationSyncedEntry, t => t.FadeOutDuration, x => FadeOutDurationOverride = x); | ||||||
|             registerArray(flickerLightsTimeSeriesSyncedEntry, t => t._FlickerLightsTimeSeries, xs => FlickerLightsTimeSeriesOverride = xs, float.Parse, sort: true); |             registerArray(flickerLightsTimeSeriesSyncedEntry, t => t.FlickerLightsTimeSeries, xs => FlickerLightsTimeSeriesOverride = xs, float.Parse, sort: true); | ||||||
|             registerArray(lyricsTimeSeriesSyncedEntry, t => t._LyricsTimeSeries, xs => LyricsTimeSeriesOverride = xs, float.Parse, sort: true); |             registerArray(lyricsTimeSeriesSyncedEntry, t => t.LyricsTimeSeries, xs => LyricsTimeSeriesOverride = xs, float.Parse, sort: true); | ||||||
|             registerStruct(beatsOffsetSyncedEntry, t => t._BeatsOffset, x => BeatsOffsetOverride = x); |             registerStruct(beatsOffsetSyncedEntry, t => t.BeatsOffset, x => BeatsOffsetOverride = x); | ||||||
|             registerStruct(colorTransitionInSyncedEntry, t => t._ColorTransitionIn, x => ColorTransitionInOverride = x); |             registerStruct(colorTransitionInSyncedEntry, t => t.ColorTransitionIn, x => ColorTransitionInOverride = x); | ||||||
|             registerStruct(colorTransitionOutSyncedEntry, t => t._ColorTransitionOut, x => ColorTransitionOutOverride = x); |             registerStruct(colorTransitionOutSyncedEntry, t => t.ColorTransitionOut, x => ColorTransitionOutOverride = x); | ||||||
|             registerClass(colorTransitionEasingSyncedEntry, t => t._ColorTransitionEasing.Name, x => ColorTransitionEasingOverride = x); |             registerClass(colorTransitionEasingSyncedEntry, t => t.ColorTransitionEasing.Name, x => ColorTransitionEasingOverride = x); | ||||||
| 
 | 
 | ||||||
|             void register<T>(SyncedEntry<T> syncedEntry, Func<CoreAudioTrack, T> getter, Action applier) |             void register<T>(SyncedEntry<T> syncedEntry, Func<IAudioTrack, T> getter, Action applier) | ||||||
|             { |             { | ||||||
|                 CSyncHackAddSyncedEntry(syncedEntry); |                 CSyncHackAddSyncedEntry(syncedEntry); | ||||||
|                 syncedEntry.SyncHostToLocal(); |                 syncedEntry.SyncHostToLocal(); | ||||||
|                 syncedEntry.Changed += (sender, args) => applier(); |                 syncedEntry.Changed += (sender, args) => applier(); | ||||||
|                 void loader(CoreAudioTrack? track) |                 void loader(IAudioTrack? track) | ||||||
|                 { |                 { | ||||||
|                     // if track is null, set everything to defaults |                     // if track is null, set everything to defaults | ||||||
|                     syncedEntry.LocalValue = track == null ? (T)syncedEntry.Entry.DefaultValue : getter(track); |                     syncedEntry.LocalValue = track == null ? (T)syncedEntry.Entry.DefaultValue : getter(track); | ||||||
|  | @ -2173,11 +2185,11 @@ namespace MuzikaGromche | ||||||
|                 entries.Add((loader, applier)); |                 entries.Add((loader, applier)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             void registerStruct<T>(SyncedEntry<T> syncedEntry, Func<CoreAudioTrack, T> getter, Action<T?> setter) where T : struct => |             void registerStruct<T>(SyncedEntry<T> syncedEntry, Func<IAudioTrack, T> getter, Action<T?> setter) where T : struct => | ||||||
|                 register(syncedEntry, getter, () => setter.Invoke(overrideTimingsSyncedEntry.Value ? syncedEntry.Value : null)); |                 register(syncedEntry, getter, () => setter.Invoke(overrideTimingsSyncedEntry.Value ? syncedEntry.Value : null)); | ||||||
|             void registerClass<T>(SyncedEntry<T> syncedEntry, Func<CoreAudioTrack, T> getter, Action<T?> setter) where T : class => |             void registerClass<T>(SyncedEntry<T> syncedEntry, Func<IAudioTrack, T> getter, Action<T?> setter) where T : class => | ||||||
|                 register(syncedEntry, getter, () => setter.Invoke(overrideTimingsSyncedEntry.Value ? syncedEntry.Value : null)); |                 register(syncedEntry, getter, () => setter.Invoke(overrideTimingsSyncedEntry.Value ? syncedEntry.Value : null)); | ||||||
|             void registerArray<T>(SyncedEntry<string> syncedEntry, Func<CoreAudioTrack, T[]> getter, Action<T[]?> setter, Func<string, T> parser, bool sort = false) where T : struct => |             void registerArray<T>(SyncedEntry<string> syncedEntry, Func<IAudioTrack, T[]> getter, Action<T[]?> setter, Func<string, T> parser, bool sort = false) where T : struct => | ||||||
|                 register(syncedEntry, |                 register(syncedEntry, | ||||||
|                     (track) => string.Join(", ", getter(track)), |                     (track) => string.Join(", ", getter(track)), | ||||||
|                     () => |                     () => | ||||||
|  | @ -2208,10 +2220,9 @@ namespace MuzikaGromche | ||||||
| 
 | 
 | ||||||
|             void load() |             void load() | ||||||
|             { |             { | ||||||
|                 var track = CurrentTrack; |  | ||||||
|                 foreach (var entry in entries) |                 foreach (var entry in entries) | ||||||
|                 { |                 { | ||||||
|                     entry.Load(track as CoreAudioTrack); |                     entry.Load(CurrentTrack); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | @ -2354,7 +2365,10 @@ namespace MuzikaGromche | ||||||
|         public void SetTrackClientRpc(string name) |         public void SetTrackClientRpc(string name) | ||||||
|         { |         { | ||||||
|             Debug.Log($"{nameof(MuzikaGromche)} SetTrackClientRpc {name}"); |             Debug.Log($"{nameof(MuzikaGromche)} SetTrackClientRpc {name}"); | ||||||
|             Config.CurrentTrack = CurrentTrack = Plugin.FindTrackNamed(name); |             if (Plugin.FindTrackNamed(name) is { } track) | ||||||
|  |             { | ||||||
|  |                 CurrentTrack = Config.OverrideCurrentTrack(track); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [ServerRpc] |         [ServerRpc] | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue