1
0
Fork 0

Enable nullable reference types

This commit is contained in:
ivan tkachenko 2025-07-30 15:27:45 +03:00
parent 0573091162
commit 6a0be0d780
2 changed files with 40 additions and 39 deletions

View File

@ -7,6 +7,7 @@
<Version>13.37.1337</Version> <Version>13.37.1337</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<!-- Prevent Publicizer Warnings from Showing --> <!-- Prevent Publicizer Warnings from Showing -->
<NoWarn>$(NoWarn);CS0436</NoWarn> <NoWarn>$(NoWarn);CS0436</NoWarn>

View File

@ -27,7 +27,7 @@ namespace MuzikaGromche
[LobbyCompatibility(CompatibilityLevel.Everyone, VersionStrictness.Patch)] [LobbyCompatibility(CompatibilityLevel.Everyone, VersionStrictness.Patch)]
public class Plugin : BaseUnityPlugin public class Plugin : BaseUnityPlugin
{ {
internal new static Config Config { get; private set; } = null; internal new static Config Config { get; private set; } = null!;
private static readonly string[] PwnLyricsVariants = [ private static readonly string[] PwnLyricsVariants = [
"", "", "", // make sure the array has enough items to index it without checking "", "", "", // make sure the array has enough items to index it without checking
@ -480,8 +480,8 @@ namespace MuzikaGromche
return tracks[trackId]; return tracks[trackId];
} }
public static Track CurrentTrack; public static Track? CurrentTrack;
public static BeatTimeState BeatTimeState; public static BeatTimeState? BeatTimeState;
public static void SetLightColor(Color color) public static void SetLightColor(Color color)
{ {
@ -624,16 +624,16 @@ namespace MuzikaGromche
public class Track public class Track
{ {
public string Name; public required string Name;
// Language of the track's lyrics. // Language of the track's lyrics.
public Language Language; public required Language Language;
// Whether this track has NSFW/explicit lyrics. // Whether this track has NSFW/explicit lyrics.
public bool IsExplicit = false; public bool IsExplicit = false;
// Wind-up time can and should be shorter than the Start audio track, // Wind-up time can and should be shorter than the Start audio track,
// so that the "pop" effect can be baked into the Start audio and kept away // so that the "pop" effect can be baked into the Start audio and kept away
// from the looped part. This also means that the light show starts before // 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. // the looped track does, so we need to sync them up as soon as we enter the Loop.
public float WindUpTimer; public required float WindUpTimer;
// Estimated number of beats per minute. Not used for light show, but might come in handy. // Estimated number of beats per minute. Not used for light show, but might come in handy.
public float Bpm => 60f / (LoadedLoop.length / Beats); public float Bpm => 60f / (LoadedLoop.length / Beats);
@ -655,11 +655,11 @@ namespace MuzikaGromche
// WAV is OK, but takes a lot of space. Try OGGVORBIS instead. // WAV is OK, but takes a lot of space. Try OGGVORBIS instead.
public AudioType AudioType = AudioType.MPEG; public AudioType AudioType = AudioType.MPEG;
public AudioClip LoadedStart; public AudioClip LoadedStart = null!;
public AudioClip LoadedLoop; public AudioClip LoadedLoop = null!;
// How often this track should be chosen, relative to the sum of weights of all tracks. // How often this track should be chosen, relative to the sum of weights of all tracks.
public SyncedEntry<int> Weight; public SyncedEntry<int> Weight = null!;
public string FileNameStart => $"{Name}Start.{Ext}"; public string FileNameStart => $"{Name}Start.{Ext}";
public string FileNameLoop => $"{Name}Loop.{Ext}"; public string FileNameLoop => $"{Name}Loop.{Ext}";
@ -743,7 +743,7 @@ namespace MuzikaGromche
// In such case, a random number chosen and updated once per loop // In such case, a random number chosen and updated once per loop
// is used to select an alternative. // is used to select an alternative.
// If the chosen alternative is an empty string, lyrics event shall be skipped. // If the chosen alternative is an empty string, lyrics event shall be skipped.
public string[] LyricsLines { get; private set; } public string[] LyricsLines { get; private set; } = [];
public (float, string)[] Lyrics public (float, string)[] Lyrics
{ {
set set
@ -989,7 +989,7 @@ namespace MuzikaGromche
private float loopOffsetBeat = float.NegativeInfinity; private float loopOffsetBeat = float.NegativeInfinity;
private static System.Random lyricsRandom = null; private static System.Random lyricsRandom = null!;
private int lyricsRandomPerLoop; private int lyricsRandomPerLoop;
@ -1140,7 +1140,7 @@ namespace MuzikaGromche
return events; return events;
} }
private SetLightsColorEvent GetColorEvent(BeatTimeSpan loopOffsetSpan, BeatTimestamp windUpOffsetTimestamp) private SetLightsColorEvent? GetColorEvent(BeatTimeSpan loopOffsetSpan, BeatTimestamp windUpOffsetTimestamp)
{ {
if (FadeOut(loopOffsetSpan) is Color c1) if (FadeOut(loopOffsetSpan) is Color c1)
{ {
@ -1403,26 +1403,26 @@ namespace MuzikaGromche
public class Config : SyncedConfig2<Config> public class Config : SyncedConfig2<Config>
{ {
public static ConfigEntry<bool> EnableColorAnimations { get; private set; } public static ConfigEntry<bool> EnableColorAnimations { get; private set; } = null!;
public static ConfigEntry<bool> DisplayLyrics { get; private set; } public static ConfigEntry<bool> DisplayLyrics { get; private set; } = null!;
public static ConfigEntry<float> AudioOffset { get; private set; } public static ConfigEntry<float> AudioOffset { get; private set; } = null!;
public static ConfigEntry<bool> SkipExplicitTracks { get; private set; } public static ConfigEntry<bool> SkipExplicitTracks { get; private set; } = null!;
public static bool ShouldSkipWindingPhase { get; private set; } = false; public static bool ShouldSkipWindingPhase { get; private set; } = false;
public static Palette PaletteOverride { get; private set; } = null; public static Palette? PaletteOverride { get; private set; } = null;
public static float? FadeOutBeatOverride { get; private set; } = null; public static float? FadeOutBeatOverride { get; private set; } = null;
public static float? FadeOutDurationOverride { get; private set; } = null; public static float? FadeOutDurationOverride { get; private set; } = null;
public static float[] FlickerLightsTimeSeriesOverride { get; private set; } = null; public static float[]? FlickerLightsTimeSeriesOverride { get; private set; } = null;
public static float[] LyricsTimeSeriesOverride { get; private set; } = null; public static float[]? LyricsTimeSeriesOverride { get; private set; } = null;
public static float? BeatsOffsetOverride { get; private set; } = null; public static float? BeatsOffsetOverride { get; private set; } = null;
public static float? ColorTransitionInOverride { get; private set; } = null; public static float? ColorTransitionInOverride { get; private set; } = null;
public static float? ColorTransitionOutOverride { get; private set; } = null; public static float? ColorTransitionOutOverride { get; private set; } = null;
public static string ColorTransitionEasingOverride { get; private set; } = null; public static string? ColorTransitionEasingOverride { get; private set; } = null;
public Config(ConfigFile configFile) : base(PluginInfo.PLUGIN_GUID) public Config(ConfigFile configFile) : base(PluginInfo.PLUGIN_GUID)
{ {
@ -1559,7 +1559,7 @@ namespace MuzikaGromche
const string section = "Palette"; const string section = "Palette";
const int maxCustomPaletteSize = 8; const int maxCustomPaletteSize = 8;
// Declare and initialize early to avoid "Use of unassigned local variable" // Declare and initialize early to avoid "Use of unassigned local variable"
SyncedEntry<int> customPaletteSizeSyncedEntry = null; SyncedEntry<int> customPaletteSizeSyncedEntry = null!;
var customPaletteSyncedEntries = new SyncedEntry<string>[maxCustomPaletteSize]; var customPaletteSyncedEntries = new SyncedEntry<string>[maxCustomPaletteSize];
var loadButton = new GenericButtonConfigItem(section, "Load Palette from the Current Track", var loadButton = new GenericButtonConfigItem(section, "Load Palette from the Current Track",
@ -1623,16 +1623,16 @@ 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<Track> Load, Action Apply)> entries = []; List<(Action<Track?> 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!;
SyncedEntry<string> flickerLightsTimeSeriesSyncedEntry = null; SyncedEntry<string> flickerLightsTimeSeriesSyncedEntry = null!;
SyncedEntry<string> lyricsTimeSeriesSyncedEntry = null; SyncedEntry<string> lyricsTimeSeriesSyncedEntry = null!;
SyncedEntry<float> beatsOffsetSyncedEntry = null; SyncedEntry<float> beatsOffsetSyncedEntry = null!;
SyncedEntry<float> colorTransitionInSyncedEntry = null; SyncedEntry<float> colorTransitionInSyncedEntry = null!;
SyncedEntry<float> colorTransitionOutSyncedEntry = null; SyncedEntry<float> colorTransitionOutSyncedEntry = null!;
SyncedEntry<string> colorTransitionEasingSyncedEntry = null; SyncedEntry<string> colorTransitionEasingSyncedEntry = null!;
var loadButton = new GenericButtonConfigItem(section, "Load Timings from the Current Track", var loadButton = new GenericButtonConfigItem(section, "Load Timings from the Current Track",
"Override custom timings with the built-in timings of the current track.", "Load", load); "Override custom timings with the built-in timings of the current track.", "Load", load);
@ -1687,7 +1687,7 @@ namespace MuzikaGromche
CSyncHackAddSyncedEntry(syncedEntry); CSyncHackAddSyncedEntry(syncedEntry);
syncedEntry.SyncHostToLocal(); syncedEntry.SyncHostToLocal();
syncedEntry.Changed += (sender, args) => applier(); syncedEntry.Changed += (sender, args) => applier();
void loader(Track track) void loader(Track? 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);
@ -1697,9 +1697,9 @@ namespace MuzikaGromche
void registerStruct<T>(SyncedEntry<T> syncedEntry, Func<Track, T> getter, Action<T?> setter) where T : struct => void registerStruct<T>(SyncedEntry<T> syncedEntry, Func<Track, 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<Track, T> getter, Action<T> setter) where T : class => void registerClass<T>(SyncedEntry<T> syncedEntry, Func<Track, 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<Track, T[]> getter, Action<T[]> setter, Func<string, T> parser, bool sort = false) where T : struct => void registerArray<T>(SyncedEntry<string> syncedEntry, Func<Track, 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)),
() => () =>
@ -1713,7 +1713,7 @@ namespace MuzikaGromche
setter.Invoke(overrideTimingsSyncedEntry.Value ? values : null); setter.Invoke(overrideTimingsSyncedEntry.Value ? values : null);
}); });
T[] parseStringArray<T>(string str, Func<string, T> parser, bool sort = false) where T : struct T[]? parseStringArray<T>(string str, Func<string, T> parser, bool sort = false) where T : struct
{ {
try try
{ {
@ -1838,7 +1838,7 @@ namespace MuzikaGromche
__instance.farAudio = __state.farAudio; __instance.farAudio = __state.farAudio;
var time = __instance.farAudio.time; var time = __instance.farAudio.time;
var delay = Plugin.CurrentTrack.LoadedStart.length - time; var delay = Plugin.CurrentTrack!.LoadedStart.length - time;
// Override screamingSFX with Loop, delayed by the remaining time of the Start audio // Override screamingSFX with Loop, delayed by the remaining time of the Start audio
__instance.creatureVoice.Stop(); __instance.creatureVoice.Stop();
@ -1853,7 +1853,7 @@ namespace MuzikaGromche
// Manage the timeline: switch color of the lights according to the current playback/beat position. // Manage the timeline: switch color of the lights according to the current playback/beat position.
if (__instance.previousState == 1 || __instance.previousState == 2) if (__instance.previousState == 1 || __instance.previousState == 2)
{ {
var events = Plugin.BeatTimeState.Update(start: __instance.farAudio, loop: __instance.creatureVoice); var events = Plugin.BeatTimeState!.Update(start: __instance.farAudio, loop: __instance.creatureVoice);
foreach (var ev in events) foreach (var ev in events)
{ {
switch (ev) switch (ev)
@ -1906,7 +1906,7 @@ namespace MuzikaGromche
internal class State internal class State
{ {
public AudioSource farAudio; public required AudioSource farAudio;
public int previousState; public required int previousState;
} }
} }