forked from nikita/muzika-gromche
Split Track into Selectable and Audio interfaces, add support for groups
This commit is contained in:
parent
47f984cd28
commit
5649a18633
|
@ -2,6 +2,7 @@
|
|||
|
||||
## MuzikaGromche 1337.420.9001
|
||||
|
||||
- Added support for tracks to rotate between multiple audio variants during a round.
|
||||
|
||||
## MuzikaGromche 1337.420.69 - It's All DiscoNnected Edition
|
||||
|
||||
|
|
|
@ -48,8 +48,8 @@ namespace MuzikaGromche
|
|||
.Select(a => $" Trying... {a}")
|
||||
];
|
||||
|
||||
public static readonly Track[] Tracks = [
|
||||
new Track
|
||||
public static readonly ISelectableTrack[] Tracks = [
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "MuzikaGromche",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -89,7 +89,7 @@ namespace MuzikaGromche
|
|||
(63, "Muzyka Gromche\nGlaza zakryty >_<"),
|
||||
],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "VseVZale",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -124,7 +124,7 @@ namespace MuzikaGromche
|
|||
(60, "Everybody shake your body"),
|
||||
],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "DeployDestroy",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -167,7 +167,7 @@ namespace MuzikaGromche
|
|||
(25, "Davaj-davaj!"),
|
||||
],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "MoyaZhittya",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -214,7 +214,7 @@ namespace MuzikaGromche
|
|||
( 30, "IT'S MY"),
|
||||
],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "Gorgorod",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -232,7 +232,7 @@ namespace MuzikaGromche
|
|||
FlickerLightsTimeSeries = [20],
|
||||
Lyrics = [],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "Durochka",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -250,7 +250,7 @@ namespace MuzikaGromche
|
|||
FlickerLightsTimeSeries = [-9],
|
||||
Lyrics = [],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "ZmeiGorynich",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -268,7 +268,7 @@ namespace MuzikaGromche
|
|||
FlickerLightsTimeSeries = [-5, 31],
|
||||
Lyrics = [],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "GodMode",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -286,7 +286,7 @@ namespace MuzikaGromche
|
|||
FlickerLightsTimeSeries = [-5],
|
||||
Lyrics = [],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "RiseAndShine",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -304,7 +304,7 @@ namespace MuzikaGromche
|
|||
FlickerLightsTimeSeries = [-5.5f, 31, 63.9f],
|
||||
Lyrics = [],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "Song2",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -322,7 +322,7 @@ namespace MuzikaGromche
|
|||
FlickerLightsTimeSeries = [2.5f],
|
||||
Lyrics = [],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "Peretasovka",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -340,7 +340,7 @@ namespace MuzikaGromche
|
|||
FlickerLightsTimeSeries = [-8, 31],
|
||||
Lyrics = [],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "Yalgaar",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -358,7 +358,7 @@ namespace MuzikaGromche
|
|||
FlickerLightsTimeSeries = [-5],
|
||||
Lyrics = [],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "Chereshnya",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -379,7 +379,7 @@ namespace MuzikaGromche
|
|||
FlickerLightsTimeSeries = [-5, 27, 29, 59, 61],
|
||||
Lyrics = [],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "PWNED",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -451,7 +451,7 @@ namespace MuzikaGromche
|
|||
(98, $"\t\t\tresolving ur private IP\nP_WNED"),
|
||||
],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "Kach",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -475,7 +475,7 @@ namespace MuzikaGromche
|
|||
FlickerLightsTimeSeries = [-120.5f, -105, -89, -8, 44, 45],
|
||||
Lyrics = [],
|
||||
},
|
||||
new Track
|
||||
new SelectableAudioTrack
|
||||
{
|
||||
Name = "BeefLiver",
|
||||
AudioType = AudioType.OGGVORBIS,
|
||||
|
@ -498,7 +498,7 @@ namespace MuzikaGromche
|
|||
},
|
||||
];
|
||||
|
||||
public static Track ChooseTrack()
|
||||
public static ISelectableTrack ChooseTrack()
|
||||
{
|
||||
var seed = RoundManager.Instance.dungeonGenerator.Generator.ChosenSeed;
|
||||
var tracks = Config.SkipExplicitTracks.Value ? [.. Tracks.Where(track => !track.IsExplicit)] : Tracks;
|
||||
|
@ -510,12 +510,12 @@ namespace MuzikaGromche
|
|||
return tracks[trackId];
|
||||
}
|
||||
|
||||
public static Track? FindTrackNamed(string name)
|
||||
public static IAudioTrack? FindTrackNamed(string name)
|
||||
{
|
||||
return Tracks.FirstOrDefault(track => track.Name == name);
|
||||
return Tracks.SelectMany(track => track.GetTracks()).FirstOrDefault(track => track.Name == name);
|
||||
}
|
||||
|
||||
internal static Track? CurrentTrack;
|
||||
internal static IAudioTrack? CurrentTrack;
|
||||
internal static BeatTimeState? BeatTimeState;
|
||||
|
||||
public static void SetLightColor(Color color)
|
||||
|
@ -562,7 +562,7 @@ namespace MuzikaGromche
|
|||
Dictionary<string, (UnityWebRequest Request, List<Action<AudioClip>> Setters)> requests = [];
|
||||
requests.EnsureCapacity(Tracks.Length * 2);
|
||||
|
||||
foreach (var track in Tracks)
|
||||
foreach (var track in Tracks.SelectMany(track => track.GetTracks()))
|
||||
{
|
||||
foreach (var (fileName, setter) in new (string, Action<AudioClip>)[]
|
||||
{
|
||||
|
@ -599,7 +599,7 @@ namespace MuzikaGromche
|
|||
#if DEBUG
|
||||
foreach (var track in Tracks)
|
||||
{
|
||||
Debug.Log($"{nameof(MuzikaGromche)} Track {track.Name} {track.LoadedIntro.length:N4} {track.LoadedLoop.length:N4}");
|
||||
track.Debug();
|
||||
}
|
||||
#endif
|
||||
Config = new Config(base.Config);
|
||||
|
@ -721,60 +721,80 @@ namespace MuzikaGromche
|
|||
}
|
||||
}
|
||||
|
||||
public class Track
|
||||
public struct SelectableTrackData()
|
||||
{
|
||||
public required string Name;
|
||||
// Name of the track, as shown in config entry UI; also used for default file names.
|
||||
public required string Name { get; init; }
|
||||
|
||||
// Language of the track's lyrics.
|
||||
public required Language Language;
|
||||
public required Language Language { get; init; }
|
||||
|
||||
// Whether this track has NSFW/explicit lyrics.
|
||||
public bool IsExplicit = false;
|
||||
public bool IsExplicit { get; init; } = false;
|
||||
|
||||
// How often this track should be chosen, relative to the sum of weights of all tracks.
|
||||
public ConfigEntry<int> Weight { get; internal set; } = null!;
|
||||
}
|
||||
|
||||
// An instance of a track which appears as a configuration entry and
|
||||
// can be selected using weighted random from a list of selectable tracks.
|
||||
public interface ISelectableTrack
|
||||
{
|
||||
// Name of the track, as shown in config entry UI; also used for default file names.
|
||||
public string Name { get; init; }
|
||||
|
||||
// Language of the track's lyrics.
|
||||
public Language Language { get; init; }
|
||||
|
||||
// Whether this track has NSFW/explicit lyrics.
|
||||
public bool IsExplicit { get; init; }
|
||||
|
||||
// How often this track should be chosen, relative to the sum of weights of all tracks.
|
||||
internal ConfigEntry<int> Weight { get; set; }
|
||||
|
||||
internal IAudioTrack[] GetTracks();
|
||||
|
||||
// Index is a non-negative monotonically increasing number of times
|
||||
// this ISelectableTrack has been played for this Jester on this day.
|
||||
// A group of tracks can use this index to rotate tracks sequentially.
|
||||
internal IAudioTrack SelectTrack(int index);
|
||||
|
||||
internal void Debug();
|
||||
}
|
||||
|
||||
// An instance of a track which has file names, timings data, palette; can be loaded and played.
|
||||
public interface IAudioTrack
|
||||
{
|
||||
// Name of the track used for default file names.
|
||||
public string Name { get; }
|
||||
|
||||
// Wind-up time can and should be shorter than the Intro audio track,
|
||||
// so that the "pop" effect can be baked into the Intro audio and kept away
|
||||
// from the looped part. This also means that the light show starts before
|
||||
// the looped track does, so we need to sync them up as soon as we enter the Loop.
|
||||
public required float WindUpTimer;
|
||||
public float WindUpTimer { get; }
|
||||
|
||||
// Estimated number of beats per minute. Not used for light show, but might come in handy.
|
||||
public float Bpm => 60f / (LoadedLoop.length / Beats);
|
||||
|
||||
// How many beats the loop segment has. The default strategy is to switch color of lights on each beat.
|
||||
public int Beats;
|
||||
public int Beats { get; }
|
||||
|
||||
// Number of beats between WindUpTimer and where looped segment starts (not the loop audio).
|
||||
public int LoopOffset = 0;
|
||||
public int LoopOffset { get; }
|
||||
public float LoopOffsetInSeconds => LoopOffset / Beats * LoadedLoop.length;
|
||||
|
||||
// Shorthand for four beats
|
||||
public int Bars
|
||||
{
|
||||
set => Beats = value * 4;
|
||||
}
|
||||
|
||||
// MPEG is basically mp3, and it can produce gaps at the start.
|
||||
// WAV is OK, but takes a lot of space. Try OGGVORBIS instead.
|
||||
public AudioType AudioType = AudioType.MPEG;
|
||||
public AudioType AudioType { get; }
|
||||
|
||||
public AudioClip LoadedIntro = null!;
|
||||
public AudioClip LoadedLoop = null!;
|
||||
public AudioClip LoadedIntro { get; internal set; }
|
||||
public AudioClip LoadedLoop { get; internal set; }
|
||||
|
||||
// How often this track should be chosen, relative to the sum of weights of all tracks.
|
||||
public ConfigEntry<int> Weight = null!;
|
||||
public string FileNameIntro { get; }
|
||||
public string FileNameLoop { get; }
|
||||
|
||||
private string? FileNameIntroOverride = null;
|
||||
public string FileNameIntro
|
||||
{
|
||||
get => FileNameIntroOverride ?? $"{Name}Intro.{Ext}";
|
||||
set => FileNameIntroOverride = value;
|
||||
}
|
||||
|
||||
private string? FileNameLoopOverride = null;
|
||||
public string FileNameLoop
|
||||
{
|
||||
get => FileNameLoopOverride ?? $"{Name}Loop.{Ext}";
|
||||
set => FileNameLoopOverride = value;
|
||||
}
|
||||
|
||||
private string Ext => AudioType switch
|
||||
public string Ext => AudioType switch
|
||||
{
|
||||
AudioType.MPEG => "mp3",
|
||||
AudioType.WAV => "wav",
|
||||
|
@ -783,28 +803,86 @@ namespace MuzikaGromche
|
|||
};
|
||||
|
||||
// Offset of beats. Bigger offset => colors will change later.
|
||||
public float BeatsOffset { get; }
|
||||
|
||||
// Offset of beats, in seconds. Bigger offset => colors will change later.
|
||||
public float BeatsOffsetInSeconds => BeatsOffset / Beats * LoadedLoop.length;
|
||||
|
||||
public float FadeOutBeat { get; }
|
||||
public float FadeOutDuration { get; }
|
||||
|
||||
// Duration of color transition, measured in beats.
|
||||
public float ColorTransitionIn { get; }
|
||||
public float ColorTransitionOut { get; }
|
||||
|
||||
// Easing function for color transitions.
|
||||
public Easing ColorTransitionEasing { get; }
|
||||
|
||||
public float[] FlickerLightsTimeSeries { get; }
|
||||
|
||||
public float[] LyricsTimeSeries { get; }
|
||||
|
||||
// Lyrics line may contain multiple tab-separated alternatives.
|
||||
// In such case, a random number chosen and updated once per loop
|
||||
// is used to select an alternative.
|
||||
// If the chosen alternative is an empty string, lyrics event shall be skipped.
|
||||
public string[] LyricsLines { get; }
|
||||
|
||||
public Palette Palette { get; }
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required float WindUpTimer { get; init; }
|
||||
public int Beats { get; init; }
|
||||
|
||||
// Shorthand for four beats
|
||||
public int Bars
|
||||
{
|
||||
init => Beats = value * 4;
|
||||
}
|
||||
|
||||
public int LoopOffset { get; init; } = 0;
|
||||
public AudioType AudioType { get; init; } = AudioType.MPEG;
|
||||
public AudioClip LoadedIntro { get; set; } = null!;
|
||||
public AudioClip LoadedLoop { get; set; } = null!;
|
||||
|
||||
private string? FileNameIntroOverride = null;
|
||||
public string FileNameIntro
|
||||
{
|
||||
get => FileNameIntroOverride ?? $"{Name}Intro.{((IAudioTrack)this).Ext}";
|
||||
init => FileNameIntroOverride = value;
|
||||
}
|
||||
|
||||
private string? FileNameLoopOverride = null;
|
||||
public string FileNameLoop
|
||||
{
|
||||
get => FileNameLoopOverride ?? $"{Name}Loop.{((IAudioTrack)this).Ext}";
|
||||
init => FileNameLoopOverride = value;
|
||||
}
|
||||
|
||||
public float _BeatsOffset = 0f;
|
||||
public float BeatsOffset
|
||||
{
|
||||
get => Config.BeatsOffsetOverride ?? _BeatsOffset;
|
||||
set => _BeatsOffset = value;
|
||||
init => _BeatsOffset = value;
|
||||
}
|
||||
|
||||
// Offset of beats, in seconds. Bigger offset => colors will change later.
|
||||
public float BeatsOffsetInSeconds => BeatsOffset / Beats * LoadedLoop.length;
|
||||
|
||||
public float _FadeOutBeat = float.NaN;
|
||||
public float FadeOutBeat
|
||||
{
|
||||
get => Config.FadeOutBeatOverride ?? _FadeOutBeat;
|
||||
set => _FadeOutBeat = value;
|
||||
init => _FadeOutBeat = value;
|
||||
}
|
||||
|
||||
public float _FadeOutDuration = 2f;
|
||||
public float FadeOutDuration
|
||||
{
|
||||
get => Config.FadeOutDurationOverride ?? _FadeOutDuration;
|
||||
set => _FadeOutDuration = value;
|
||||
init => _FadeOutDuration = value;
|
||||
}
|
||||
|
||||
// Duration of color transition, measured in beats.
|
||||
|
@ -812,14 +890,14 @@ namespace MuzikaGromche
|
|||
public float ColorTransitionIn
|
||||
{
|
||||
get => Config.ColorTransitionInOverride ?? _ColorTransitionIn;
|
||||
set => _ColorTransitionIn = value;
|
||||
init => _ColorTransitionIn = value;
|
||||
}
|
||||
|
||||
public float _ColorTransitionOut = 0.25f;
|
||||
public float ColorTransitionOut
|
||||
{
|
||||
get => Config.ColorTransitionOutOverride ?? _ColorTransitionOut;
|
||||
set => _ColorTransitionOut = value;
|
||||
init => _ColorTransitionOut = value;
|
||||
}
|
||||
|
||||
// Easing function for color transitions.
|
||||
|
@ -829,14 +907,14 @@ namespace MuzikaGromche
|
|||
get => Config.ColorTransitionEasingOverride != null
|
||||
? Easing.FindByName(Config.ColorTransitionEasingOverride)
|
||||
: _ColorTransitionEasing;
|
||||
set => _ColorTransitionEasing = value;
|
||||
init => _ColorTransitionEasing = value;
|
||||
}
|
||||
|
||||
public float[] _FlickerLightsTimeSeries = [];
|
||||
public float[] FlickerLightsTimeSeries
|
||||
{
|
||||
get => Config.FlickerLightsTimeSeriesOverride ?? _FlickerLightsTimeSeries;
|
||||
set
|
||||
init
|
||||
{
|
||||
Array.Sort(value);
|
||||
_FlickerLightsTimeSeries = value;
|
||||
|
@ -877,6 +955,53 @@ namespace MuzikaGromche
|
|||
}
|
||||
}
|
||||
|
||||
// Standalone, top-level, selectable audio track
|
||||
public class SelectableAudioTrack : CoreAudioTrack, ISelectableTrack
|
||||
{
|
||||
public required Language Language { get; init; }
|
||||
public bool IsExplicit { get; init; } = false;
|
||||
ConfigEntry<int> ISelectableTrack.Weight { get; set; } = null!;
|
||||
|
||||
IAudioTrack[] ISelectableTrack.GetTracks() => [this];
|
||||
|
||||
IAudioTrack ISelectableTrack.SelectTrack(int index) => this;
|
||||
|
||||
void ISelectableTrack.Debug()
|
||||
{
|
||||
Debug.Log($"{nameof(MuzikaGromche)} Track \"{Name}\", Intro={LoadedIntro.length:N4}, Loop={LoadedLoop.length:N4}");
|
||||
}
|
||||
}
|
||||
|
||||
public class SelectableTracksGroup : ISelectableTrack
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required Language Language { get; init; }
|
||||
public bool IsExplicit { get; init; } = false;
|
||||
ConfigEntry<int> ISelectableTrack.Weight { get; set; } = null!;
|
||||
|
||||
public required IAudioTrack[] Tracks;
|
||||
|
||||
IAudioTrack[] ISelectableTrack.GetTracks() => Tracks;
|
||||
|
||||
IAudioTrack ISelectableTrack.SelectTrack(int index)
|
||||
{
|
||||
if (Tracks.Length == 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Tracks list is empty");
|
||||
}
|
||||
return Mod.Index(Tracks, index);
|
||||
}
|
||||
|
||||
void ISelectableTrack.Debug()
|
||||
{
|
||||
Debug.Log($"{nameof(MuzikaGromche)} Track Group \"{Name}\", Count={Tracks.Length}");
|
||||
foreach (var (track, index) in Tracks.Select((x, i) => (x, i)))
|
||||
{
|
||||
Debug.Log($"{nameof(MuzikaGromche)} Track {index} \"{track.Name}\", Intro={track.LoadedIntro.length:N4}, Loop={track.LoadedLoop.length:N4}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly record struct BeatTimestamp
|
||||
{
|
||||
// Number of beats in the loop audio segment.
|
||||
|
@ -1252,7 +1377,7 @@ namespace MuzikaGromche
|
|||
|
||||
class BeatTimeState
|
||||
{
|
||||
private readonly Track track;
|
||||
private readonly IAudioTrack track;
|
||||
|
||||
private readonly JesterAudioSourcesState AudioState;
|
||||
|
||||
|
@ -1270,7 +1395,7 @@ namespace MuzikaGromche
|
|||
|
||||
private bool WindUpZeroBeatEventTriggered = false;
|
||||
|
||||
public BeatTimeState(Track track)
|
||||
public BeatTimeState(IAudioTrack track)
|
||||
{
|
||||
if (LyricsRandom == null)
|
||||
{
|
||||
|
@ -1853,7 +1978,7 @@ namespace MuzikaGromche
|
|||
|
||||
void load()
|
||||
{
|
||||
var palette = Plugin.CurrentTrack?._Palette ?? Palette.DEFAULT;
|
||||
var palette = (Plugin.CurrentTrack as CoreAudioTrack)?._Palette ?? Palette.DEFAULT;
|
||||
var colors = palette.Colors;
|
||||
var count = Math.Min(colors.Count(), maxCustomPaletteSize);
|
||||
|
||||
|
@ -1886,7 +2011,7 @@ namespace MuzikaGromche
|
|||
const string section = "Timings";
|
||||
var colorTransitionRange = new AcceptableValueRange<float>(0f, 1f);
|
||||
// Declare and initialize early to avoid "Use of unassigned local variable"
|
||||
List<(Action<Track?> Load, Action Apply)> entries = [];
|
||||
List<(Action<CoreAudioTrack?> Load, Action Apply)> entries = [];
|
||||
SyncedEntry<bool> overrideTimingsSyncedEntry = null!;
|
||||
SyncedEntry<float> fadeOutBeatSyncedEntry = null!;
|
||||
SyncedEntry<float> fadeOutDurationSyncedEntry = null!;
|
||||
|
@ -1945,12 +2070,12 @@ namespace MuzikaGromche
|
|||
registerStruct(colorTransitionOutSyncedEntry, t => t._ColorTransitionOut, x => ColorTransitionOutOverride = x);
|
||||
registerClass(colorTransitionEasingSyncedEntry, t => t._ColorTransitionEasing.Name, x => ColorTransitionEasingOverride = x);
|
||||
|
||||
void register<T>(SyncedEntry<T> syncedEntry, Func<Track, T> getter, Action applier)
|
||||
void register<T>(SyncedEntry<T> syncedEntry, Func<CoreAudioTrack, T> getter, Action applier)
|
||||
{
|
||||
CSyncHackAddSyncedEntry(syncedEntry);
|
||||
syncedEntry.SyncHostToLocal();
|
||||
syncedEntry.Changed += (sender, args) => applier();
|
||||
void loader(Track? track)
|
||||
void loader(CoreAudioTrack? track)
|
||||
{
|
||||
// if track is null, set everything to defaults
|
||||
syncedEntry.LocalValue = track == null ? (T)syncedEntry.Entry.DefaultValue : getter(track);
|
||||
|
@ -1958,11 +2083,11 @@ namespace MuzikaGromche
|
|||
entries.Add((loader, applier));
|
||||
}
|
||||
|
||||
void registerStruct<T>(SyncedEntry<T> syncedEntry, Func<Track, T> getter, Action<T?> setter) where T : struct =>
|
||||
void registerStruct<T>(SyncedEntry<T> syncedEntry, Func<CoreAudioTrack, T> getter, Action<T?> setter) where T : struct =>
|
||||
register(syncedEntry, getter, () => setter.Invoke(overrideTimingsSyncedEntry.Value ? syncedEntry.Value : null));
|
||||
void registerClass<T>(SyncedEntry<T> syncedEntry, Func<Track, T> getter, Action<T?> setter) where T : class =>
|
||||
void registerClass<T>(SyncedEntry<T> syncedEntry, Func<CoreAudioTrack, T> getter, Action<T?> setter) where T : class =>
|
||||
register(syncedEntry, getter, () => setter.Invoke(overrideTimingsSyncedEntry.Value ? syncedEntry.Value : null));
|
||||
void registerArray<T>(SyncedEntry<string> syncedEntry, Func<Track, T[]> getter, Action<T[]?> setter, Func<string, T> parser, bool sort = false) where T : struct =>
|
||||
void registerArray<T>(SyncedEntry<string> syncedEntry, Func<CoreAudioTrack, T[]> getter, Action<T[]?> setter, Func<string, T> parser, bool sort = false) where T : struct =>
|
||||
register(syncedEntry,
|
||||
(track) => string.Join(", ", getter(track)),
|
||||
() =>
|
||||
|
@ -1996,7 +2121,7 @@ namespace MuzikaGromche
|
|||
var track = Plugin.CurrentTrack;
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
entry.Load(track);
|
||||
entry.Load(track as CoreAudioTrack);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2043,6 +2168,11 @@ namespace MuzikaGromche
|
|||
|
||||
class MuzikaGromcheJesterNetworkBehaviour : NetworkBehaviour
|
||||
{
|
||||
// Number of times a selected track has been played.
|
||||
// Increases by 1 with each ChooseTrackServerRpc call.
|
||||
// Resets on SettingChanged.
|
||||
private int SelectedTrackIndex = 0;
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
ChooseTrackDeferred();
|
||||
|
@ -2069,6 +2199,7 @@ namespace MuzikaGromche
|
|||
|
||||
private void ChooseTrackDeferredDelegate(object sender, EventArgs e)
|
||||
{
|
||||
SelectedTrackIndex = 0;
|
||||
ChooseTrackDeferred();
|
||||
}
|
||||
|
||||
|
@ -2099,9 +2230,11 @@ namespace MuzikaGromche
|
|||
[ServerRpc]
|
||||
public void ChooseTrackServerRpc()
|
||||
{
|
||||
var track = Plugin.ChooseTrack();
|
||||
Debug.Log($"{nameof(MuzikaGromche)} ChooseTrackServerRpc {track.Name}");
|
||||
SetTrackClientRpc(track.Name);
|
||||
var selectableTrack = Plugin.ChooseTrack();
|
||||
var audioTrack = selectableTrack.SelectTrack(SelectedTrackIndex);
|
||||
Debug.Log($"{nameof(MuzikaGromche)} ChooseTrackServerRpc {selectableTrack.Name} #{SelectedTrackIndex} {audioTrack.Name}");
|
||||
SetTrackClientRpc(audioTrack.Name);
|
||||
SelectedTrackIndex += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2195,6 +2328,8 @@ namespace MuzikaGromche
|
|||
{
|
||||
Plugin.ResetLightColor();
|
||||
DiscoBallManager.Disable();
|
||||
// Rotate track groups
|
||||
__instance.GetComponent<MuzikaGromcheJesterNetworkBehaviour>()?.ChooseTrackServerRpc();
|
||||
}
|
||||
|
||||
if (__instance.previousState == 2 && __state.previousState != 2)
|
||||
|
|
Loading…
Reference in New Issue