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>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<!-- Prevent Publicizer Warnings from Showing -->
<NoWarn>$(NoWarn);CS0436</NoWarn>

View File

@ -27,7 +27,7 @@ namespace MuzikaGromche
[LobbyCompatibility(CompatibilityLevel.Everyone, VersionStrictness.Patch)]
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 = [
"", "", "", // make sure the array has enough items to index it without checking
@ -480,8 +480,8 @@ namespace MuzikaGromche
return tracks[trackId];
}
public static Track CurrentTrack;
public static BeatTimeState BeatTimeState;
public static Track? CurrentTrack;
public static BeatTimeState? BeatTimeState;
public static void SetLightColor(Color color)
{
@ -624,16 +624,16 @@ namespace MuzikaGromche
public class Track
{
public string Name;
public required string Name;
// Language of the track's lyrics.
public Language Language;
public required Language Language;
// Whether this track has NSFW/explicit lyrics.
public bool IsExplicit = false;
// 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
// 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 float WindUpTimer;
public required float WindUpTimer;
// Estimated number of beats per minute. Not used for light show, but might come in handy.
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.
public AudioType AudioType = AudioType.MPEG;
public AudioClip LoadedStart;
public AudioClip LoadedLoop;
public AudioClip LoadedStart = null!;
public AudioClip LoadedLoop = null!;
// 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 FileNameLoop => $"{Name}Loop.{Ext}";
@ -743,7 +743,7 @@ namespace MuzikaGromche
// 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; private set; }
public string[] LyricsLines { get; private set; } = [];
public (float, string)[] Lyrics
{
set
@ -989,7 +989,7 @@ namespace MuzikaGromche
private float loopOffsetBeat = float.NegativeInfinity;
private static System.Random lyricsRandom = null;
private static System.Random lyricsRandom = null!;
private int lyricsRandomPerLoop;
@ -1140,7 +1140,7 @@ namespace MuzikaGromche
return events;
}
private SetLightsColorEvent GetColorEvent(BeatTimeSpan loopOffsetSpan, BeatTimestamp windUpOffsetTimestamp)
private SetLightsColorEvent? GetColorEvent(BeatTimeSpan loopOffsetSpan, BeatTimestamp windUpOffsetTimestamp)
{
if (FadeOut(loopOffsetSpan) is Color c1)
{
@ -1403,26 +1403,26 @@ namespace MuzikaGromche
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 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? FadeOutDurationOverride { get; private set; } = null;
public static float[] FlickerLightsTimeSeriesOverride { get; private set; } = null;
public static float[] LyricsTimeSeriesOverride { 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;
public static string? ColorTransitionEasingOverride { get; private set; } = null;
public Config(ConfigFile configFile) : base(PluginInfo.PLUGIN_GUID)
{
@ -1559,7 +1559,7 @@ namespace MuzikaGromche
const string section = "Palette";
const int maxCustomPaletteSize = 8;
// 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 loadButton = new GenericButtonConfigItem(section, "Load Palette from the Current Track",
@ -1623,16 +1623,16 @@ 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 = [];
SyncedEntry<bool> overrideTimingsSyncedEntry = null;
SyncedEntry<float> fadeOutBeatSyncedEntry = null;
SyncedEntry<float> fadeOutDurationSyncedEntry = null;
SyncedEntry<string> flickerLightsTimeSeriesSyncedEntry = null;
SyncedEntry<string> lyricsTimeSeriesSyncedEntry = null;
SyncedEntry<float> beatsOffsetSyncedEntry = null;
SyncedEntry<float> colorTransitionInSyncedEntry = null;
SyncedEntry<float> colorTransitionOutSyncedEntry = null;
SyncedEntry<string> colorTransitionEasingSyncedEntry = null;
List<(Action<Track?> Load, Action Apply)> entries = [];
SyncedEntry<bool> overrideTimingsSyncedEntry = null!;
SyncedEntry<float> fadeOutBeatSyncedEntry = null!;
SyncedEntry<float> fadeOutDurationSyncedEntry = null!;
SyncedEntry<string> flickerLightsTimeSeriesSyncedEntry = null!;
SyncedEntry<string> lyricsTimeSeriesSyncedEntry = null!;
SyncedEntry<float> beatsOffsetSyncedEntry = null!;
SyncedEntry<float> colorTransitionInSyncedEntry = null!;
SyncedEntry<float> colorTransitionOutSyncedEntry = null!;
SyncedEntry<string> colorTransitionEasingSyncedEntry = null!;
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);
@ -1687,7 +1687,7 @@ namespace MuzikaGromche
CSyncHackAddSyncedEntry(syncedEntry);
syncedEntry.SyncHostToLocal();
syncedEntry.Changed += (sender, args) => applier();
void loader(Track track)
void loader(Track? track)
{
// if track is null, set everything to defaults
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 =>
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));
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,
(track) => string.Join(", ", getter(track)),
() =>
@ -1713,7 +1713,7 @@ namespace MuzikaGromche
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
{
@ -1838,7 +1838,7 @@ namespace MuzikaGromche
__instance.farAudio = __state.farAudio;
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
__instance.creatureVoice.Stop();
@ -1853,7 +1853,7 @@ namespace MuzikaGromche
// Manage the timeline: switch color of the lights according to the current playback/beat position.
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)
{
switch (ev)
@ -1906,7 +1906,7 @@ namespace MuzikaGromche
internal class State
{
public AudioSource farAudio;
public int previousState;
public required AudioSource farAudio;
public required int previousState;
}
}