Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of WipeSong v1.0.5
plugins/WipeSong/aj.WipeSong.dll
Decompiled 16 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Networking; using WipeSong.Configuration; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("aj.WipeSong")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.5.0")] [assembly: AssemblyInformationalVersion("1.0.5")] [assembly: AssemblyProduct("WipeSong")] [assembly: AssemblyTitle("aj.WipeSong")] [assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was created with the assistance of generative AI (code); see the README credits for which assets.")] [assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic")] [assembly: AssemblyVersion("1.0.5.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace WipeSong { [HarmonyPatch] internal static class Patches { [HarmonyPatch(typeof(StartOfRound), "Start")] [HarmonyPostfix] private static void StartOfRoundStarted(StartOfRound __instance) { SongNet.Register(); ((Component)__instance).gameObject.AddComponent<SongPlayer>(); } [HarmonyPatch(typeof(StartOfRound), "ShipLeaveAutomatically")] [HarmonyPrefix] private static void BeforeShipLeavesAutomatically(StartOfRound __instance, bool leavingOnMidnight, out bool __state) { __state = !leavingOnMidnight && !__instance.shipLeftAutomatically && !__instance.shipIsLeaving; } [HarmonyPatch(typeof(StartOfRound), "ShipLeaveAutomatically")] [HarmonyPostfix] private static void AfterShipLeavesAutomatically(StartOfRound __instance, bool __state) { if (__state && __instance.shipLeftAutomatically) { SongPlayer.Begin(); SongNet.HostTellEveryone(); } } [HarmonyPatch(typeof(StartOfRound), "EndOfGameClientRpc")] [HarmonyPrefix] private static void EndOfDay() { SongPlayer.End(); } } [BepInPlugin("WipeSong", "WipeSong", "1.0.5")] public class Plugin : BaseUnityPlugin { private const string SongFile = "Crazy.ogg"; internal static ManualLogSource Logger; internal static AudioClip? Song; internal static PluginConfig BoundConfig { get; private set; } private void Awake() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) Logger = ((BaseUnityPlugin)this).Logger; BoundConfig = new PluginConfig(((BaseUnityPlugin)this).Config); Song = LoadSong(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "Crazy.ogg")); new Harmony("WipeSong").PatchAll(typeof(Patches)); Logger.LogInfo((object)"Plugin WipeSong is loaded!"); } private static AudioClip? LoadSong(string path) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Invalid comparison between Unknown and I4 if (!File.Exists(path)) { Logger.LogError((object)("Song not found at " + path + "; no music when the crew dies.")); return null; } UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip("file:///" + path.Replace('\\', '/'), (AudioType)14); try { ((DownloadHandlerAudioClip)audioClip.downloadHandler).compressed = true; audioClip.SendWebRequest(); while (!audioClip.isDone) { } if ((int)audioClip.result != 1) { Logger.LogError((object)("Couldn't load the song (" + audioClip.error + "); no music when the crew dies.")); return null; } AudioClip content = DownloadHandlerAudioClip.GetContent(audioClip); ((Object)content).name = "WipeSong"; return content; } finally { ((IDisposable)audioClip)?.Dispose(); } } } internal static class SongNet { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnStart; } private const string StartMessage = "aj.WipeSong.Start"; private static CustomMessagingManager? Messages { get { if (!((Object)(object)NetworkManager.Singleton != (Object)null)) { return null; } return NetworkManager.Singleton.CustomMessagingManager; } } internal static void Register() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown CustomMessagingManager messages = Messages; if (messages == null) { Plugin.Logger.LogWarning((object)"No network messaging; each player's song starts on their own game's cue only."); return; } object obj = <>O.<0>__OnStart; if (obj == null) { HandleNamedMessageDelegate val = OnStart; <>O.<0>__OnStart = val; obj = (object)val; } messages.RegisterNamedMessageHandler("aj.WipeSong.Start", (HandleNamedMessageDelegate)obj); } internal static void Unregister() { CustomMessagingManager? messages = Messages; if (messages != null) { messages.UnregisterNamedMessageHandler("aj.WipeSong.Start"); } } internal unsafe static void HostTellEveryone() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; CustomMessagingManager messages = Messages; if ((Object)(object)singleton == (Object)null || !singleton.IsServer || messages == null) { return; } List<ulong> list = singleton.ConnectedClientsIds.Where((ulong id) => id != 0).ToList(); if (list.Count == 0) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(0, (Allocator)2, -1); try { messages.SendNamedMessage("aj.WipeSong.Start", (IReadOnlyList<ulong>)list, val, (NetworkDelivery)2); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void OnStart(ulong sender, FastBufferReader reader) { if (sender == 0L) { SongPlayer.Begin(); } } } internal class SongPlayer : MonoBehaviour { private enum State { Idle, FadingIn, Playing, FadingOut } private const float SongStartSeconds = 10f; private static SongPlayer? instance; private AudioSource source; private State state; private void Awake() { instance = this; source = ((Component)this).gameObject.AddComponent<AudioSource>(); source.playOnAwake = false; source.loop = false; source.spatialBlend = 0f; source.bypassReverbZones = true; source.bypassListenerEffects = true; source.priority = 0; ((Behaviour)this).enabled = false; } internal static void Begin() { if ((Object)(object)instance != (Object)null) { instance.StartSong(); } } internal static void End() { if ((Object)(object)instance != (Object)null && instance.state != State.Idle) { instance.state = State.FadingOut; } } private void StartSong() { AudioClip song = Plugin.Song; if (state == State.Idle && !((Object)(object)song == (Object)null) && !(Plugin.BoundConfig.Volume.Value <= 0f)) { source.clip = song; source.volume = 0f; source.Play(); source.time = Mathf.Min(10f, song.length - 0.1f); state = State.FadingIn; ((Behaviour)this).enabled = true; } } private void Update() { if (!source.isPlaying) { StopSong(); return; } float num = Mathf.Clamp01(Plugin.BoundConfig.Volume.Value); switch (state) { case State.FadingIn: source.volume = Step(source.volume, num, Plugin.BoundConfig.FadeInSeconds.Value, num); if (source.volume >= num) { state = State.Playing; } break; case State.Playing: source.volume = num; break; case State.FadingOut: source.volume = Step(source.volume, 0f, Plugin.BoundConfig.FadeOutSeconds.Value, num); if (source.volume <= 0f) { StopSong(); } break; } } private void StopSong() { source.Stop(); state = State.Idle; ((Behaviour)this).enabled = false; } private static float Step(float volume, float target, float seconds, float full) { if (seconds <= 0f || full <= 0f) { return target; } return Mathf.MoveTowards(volume, target, full / seconds * Time.deltaTime); } private void OnDestroy() { if ((Object)(object)instance == (Object)(object)this) { instance = null; } SongNet.Unregister(); } } public static class PluginInfo { public const string PLUGIN_GUID = "WipeSong"; public const string PLUGIN_NAME = "WipeSong"; public const string PLUGIN_VERSION = "1.0.5"; } } namespace WipeSong.Configuration { internal class PluginConfig { public ConfigEntry<float> Volume; public ConfigEntry<float> FadeInSeconds; public ConfigEntry<float> FadeOutSeconds; public PluginConfig(ConfigFile cfg) { Volume = cfg.Bind<float>("Song", "Volume", 0.6f, "How loud the song plays once faded in (0 = off, 1 = full). Each player's own setting; the game's master volume still applies."); FadeInSeconds = cfg.Bind<float>("Song", "Fade in", 1f, "Seconds the song takes to fade in after the last player dies."); FadeOutSeconds = cfg.Bind<float>("Song", "Fade out", 1f, "Seconds the song takes to fade out once the ship has left and the end-of-day results come up."); } } }