forked from nikita/muzika-gromche
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
|
@ -918,6 +918,31 @@ 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