diff --git a/MuzikaGromche/Plugin.cs b/MuzikaGromche/Plugin.cs index b4a9a28..6538c9a 100644 --- a/MuzikaGromche/Plugin.cs +++ b/MuzikaGromche/Plugin.cs @@ -917,7 +917,32 @@ namespace MuzikaGromche 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. // Suitable to declare elemnents of SelectableTracksGroup and as a base for standalone selectable tracks. public class CoreAudioTrack : IAudioTrack @@ -951,56 +976,17 @@ namespace MuzikaGromche init => FileNameLoopOverride = value; } - public float _BeatsOffset = 0f; - public float BeatsOffset - { - get => Config.BeatsOffsetOverride ?? _BeatsOffset; - init => _BeatsOffset = value; - } - - 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 BeatsOffset { get; init; } = 0f; + public float FadeOutBeat { get; init; } = float.NaN; + public float FadeOutDuration { get; init; } = 2f; + public float ColorTransitionIn { get; init; } = 0.25f; + public float ColorTransitionOut { get; init; } = 0.25f; + public Easing ColorTransitionEasing { get; init; } = Easing.OutExpo; public float[] _FlickerLightsTimeSeries = []; public float[] FlickerLightsTimeSeries { - get => Config.FlickerLightsTimeSeriesOverride ?? _FlickerLightsTimeSeries; + get => _FlickerLightsTimeSeries; init { Array.Sort(value); @@ -1008,12 +994,7 @@ namespace MuzikaGromche } } - public float[] _LyricsTimeSeries = []; - public float[] LyricsTimeSeries - { - get => Config.LyricsTimeSeriesOverride ?? _LyricsTimeSeries; - private set => _LyricsTimeSeries = value; - } + public float[] LyricsTimeSeries { get; private set; } = []; // Lyrics line may contain multiple tab-separated alternatives. // 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 => Config.PaletteOverride ?? _Palette; - set => _Palette = value; - } + public Palette Palette { get; set; } = Palette.DEFAULT; } // Standalone, top-level, selectable audio track @@ -1853,9 +1829,6 @@ namespace MuzikaGromche : SyncedConfig2 #endif { - // Latest set track, used for loading palette and timings. - public static IAudioTrack? CurrentTrack { get; internal set; } = null; - public static ConfigEntry DisplayLyrics { get; private set; } = null!; public static ConfigEntry AudioOffset { get; private set; } = null!; @@ -1867,16 +1840,45 @@ namespace MuzikaGromche public static bool ExtrapolateTime { get; private set; } = true; 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; - public static float? FadeOutDurationOverride { get; private set; } = null; - public static float[]? FlickerLightsTimeSeriesOverride { get; private set; } = null; - public static float[]? LyricsTimeSeriesOverride { get; private set; } = null; - public static float? BeatsOffsetOverride { get; private set; } = null; - public static float? ColorTransitionInOverride { get; private set; } = null; - public static float? ColorTransitionOutOverride { get; private set; } = null; - public static string? ColorTransitionEasingOverride { get; private set; } = null; + private class AudioTrackWithConfigOverride(IAudioTrack track) : ProxyAudioTrack(track), IAudioTrack + { + float IAudioTrack.BeatsOffset => BeatsOffsetOverride ?? Track.BeatsOffset; + + float IAudioTrack.FadeOutBeat => FadeOutBeatOverride ?? Track.FadeOutBeat; + + float IAudioTrack.FadeOutDuration => FadeOutDurationOverride ?? Track.FadeOutDuration; + + 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) #if DEBUG @@ -1955,6 +1957,16 @@ namespace MuzikaGromche #endif } + internal static IAudioTrack OverrideCurrentTrack(IAudioTrack track) + { +#if DEBUG + CurrentTrack = track; + return new AudioTrackWithConfigOverride(track); +#else + return track; +#endif + } + #if DEBUG // HACK because CSync doesn't provide an API to register a list of config entries // See https://github.com/lc-sigurd/CSync/issues/11 @@ -2068,7 +2080,7 @@ namespace MuzikaGromche void load() { - var palette = (CurrentTrack as CoreAudioTrack)?._Palette ?? Palette.DEFAULT; + var palette = CurrentTrack?.Palette ?? Palette.DEFAULT; var colors = palette.Colors; var count = Math.Min(colors.Count(), maxCustomPaletteSize); @@ -2101,7 +2113,7 @@ namespace MuzikaGromche const string section = "Timings"; var colorTransitionRange = new AcceptableValueRange(0f, 1f); // Declare and initialize early to avoid "Use of unassigned local variable" - List<(Action Load, Action Apply)> entries = []; + List<(Action Load, Action Apply)> entries = []; SyncedEntry overrideTimingsSyncedEntry = null!; SyncedEntry fadeOutBeatSyncedEntry = null!; SyncedEntry fadeOutDurationSyncedEntry = null!; @@ -2151,21 +2163,21 @@ namespace MuzikaGromche LethalConfigManager.AddConfigItem(new FloatSliderConfigItem(colorTransitionOutSyncedEntry.Entry, floatSliderOptions)); LethalConfigManager.AddConfigItem(new TextDropDownConfigItem(colorTransitionEasingSyncedEntry.Entry, Default(new TextDropDownOptions()))); - registerStruct(fadeOutBeatSyncedEntry, t => t._FadeOutBeat, x => FadeOutBeatOverride = x); - registerStruct(fadeOutDurationSyncedEntry, t => t._FadeOutDuration, x => FadeOutDurationOverride = x); - registerArray(flickerLightsTimeSeriesSyncedEntry, t => t._FlickerLightsTimeSeries, xs => FlickerLightsTimeSeriesOverride = 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(colorTransitionInSyncedEntry, t => t._ColorTransitionIn, x => ColorTransitionInOverride = x); - registerStruct(colorTransitionOutSyncedEntry, t => t._ColorTransitionOut, x => ColorTransitionOutOverride = x); - registerClass(colorTransitionEasingSyncedEntry, t => t._ColorTransitionEasing.Name, x => ColorTransitionEasingOverride = x); + registerStruct(fadeOutBeatSyncedEntry, t => t.FadeOutBeat, x => FadeOutBeatOverride = x); + registerStruct(fadeOutDurationSyncedEntry, t => t.FadeOutDuration, x => FadeOutDurationOverride = x); + registerArray(flickerLightsTimeSeriesSyncedEntry, t => t.FlickerLightsTimeSeries, xs => FlickerLightsTimeSeriesOverride = 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(colorTransitionInSyncedEntry, t => t.ColorTransitionIn, x => ColorTransitionInOverride = x); + registerStruct(colorTransitionOutSyncedEntry, t => t.ColorTransitionOut, x => ColorTransitionOutOverride = x); + registerClass(colorTransitionEasingSyncedEntry, t => t.ColorTransitionEasing.Name, x => ColorTransitionEasingOverride = x); - void register(SyncedEntry syncedEntry, Func getter, Action applier) + void register(SyncedEntry syncedEntry, Func getter, Action applier) { CSyncHackAddSyncedEntry(syncedEntry); syncedEntry.SyncHostToLocal(); syncedEntry.Changed += (sender, args) => applier(); - void loader(CoreAudioTrack? track) + void loader(IAudioTrack? track) { // if track is null, set everything to defaults syncedEntry.LocalValue = track == null ? (T)syncedEntry.Entry.DefaultValue : getter(track); @@ -2173,11 +2185,11 @@ namespace MuzikaGromche entries.Add((loader, applier)); } - void registerStruct(SyncedEntry syncedEntry, Func getter, Action setter) where T : struct => + void registerStruct(SyncedEntry syncedEntry, Func getter, Action setter) where T : struct => register(syncedEntry, getter, () => setter.Invoke(overrideTimingsSyncedEntry.Value ? syncedEntry.Value : null)); - void registerClass(SyncedEntry syncedEntry, Func getter, Action setter) where T : class => + void registerClass(SyncedEntry syncedEntry, Func getter, Action setter) where T : class => register(syncedEntry, getter, () => setter.Invoke(overrideTimingsSyncedEntry.Value ? syncedEntry.Value : null)); - void registerArray(SyncedEntry syncedEntry, Func getter, Action setter, Func parser, bool sort = false) where T : struct => + void registerArray(SyncedEntry syncedEntry, Func getter, Action setter, Func parser, bool sort = false) where T : struct => register(syncedEntry, (track) => string.Join(", ", getter(track)), () => @@ -2208,10 +2220,9 @@ namespace MuzikaGromche void load() { - var track = CurrentTrack; foreach (var entry in entries) { - entry.Load(track as CoreAudioTrack); + entry.Load(CurrentTrack); } } @@ -2354,7 +2365,10 @@ namespace MuzikaGromche public void SetTrackClientRpc(string name) { Debug.Log($"{nameof(MuzikaGromche)} SetTrackClientRpc {name}"); - Config.CurrentTrack = CurrentTrack = Plugin.FindTrackNamed(name); + if (Plugin.FindTrackNamed(name) is { } track) + { + CurrentTrack = Config.OverrideCurrentTrack(track); + } } [ServerRpc]