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 QueenOfTheLosers v1.1.1
QueenOfTheLosers.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using QueenOfTheLosers.Modifiers; using REPOLib.Modules; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("QueenOfTheLosers")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+57482133f365a4a9ddb7a08bf665b8b072be83cd")] [assembly: AssemblyProduct("QueenOfTheLosers")] [assembly: AssemblyTitle("QueenOfTheLosers")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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 QueenOfTheLosers { public struct PlayerID : IEquatable<PlayerID> { private static PlayerID local; private string steamID; public static PlayerID Local { get { ref string reference = ref local.steamID; if (reference == null) { reference = SemiFunc.PlayerAvatarLocal()?.steamID; } return local; } } public static bool LocalSteamIDFound => Local.HasSteamID; public string SteamID => steamID ?? (steamID = Local.steamID); public PlayerAvatar? Avatar => ((Object)(object)GameDirector.instance == (Object)null) ? null : SemiFunc.PlayerAvatarGetFromSteamID(SteamID); public bool IsLocal => SteamID == Local.SteamID; public bool HasSteamID => SteamID != null; [return: NotNullIfNotNull("avatar")] public static PlayerID? FromAvatar(PlayerAvatar avatar) { PlayerID? result; if (!((Object)(object)avatar == (Object)null)) { PlayerID value = default(PlayerID); value.steamID = avatar.steamID; result = value; } else { result = null; } return result; } [return: NotNullIfNotNull("avatar")] public static implicit operator PlayerID?(PlayerAvatar avatar) { return FromAvatar(avatar); } public override string ToString() { return "PlayerID: " + (SteamID?.ToString() ?? "Local Unknown"); } public override int GetHashCode() { return (!(SteamID == Local.SteamID)) ? SteamID.GetHashCode() : 0; } public override readonly bool Equals(object? obj) { return obj is PlayerID other && Equals(other); } public readonly bool Equals(PlayerID other) { return this == other; } public static bool operator ==(PlayerID left, PlayerID right) { return left.SteamID == right.SteamID; } public static bool operator !=(PlayerID left, PlayerID right) { return left.SteamID != right.SteamID; } } public static class PlayerSettingSyncer { private static NetworkedEvent SyncEvent = null; private static long SequenceNumber; private static bool isDirty; public static Dictionary<string, NetworkedPlayerSetting> Settings = new Dictionary<string, NetworkedPlayerSetting>(); public static void Init() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown SyncEvent = new NetworkedEvent("RT0405.QueenOfTheLosers.Sync", (Action<EventData>)delegate(EventData e) { if (!RecieveMessage(e)) { QueenOfTheLosers.Logger.LogWarning((object)"invalid message recieved in PlayerSettingSyncer"); } }); } public static void SendIfDirty() { if (isDirty) { SendPlayerSettings(); } } public static void SetDirty() { isDirty = true; } public static void RegisterValue(string id, NetworkedPlayerSetting value) { Settings.Add(id, value); } public static void SendPlayerSettings() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) if (!PlayerID.Local.HasSteamID) { return; } Hashtable val = new Hashtable(); foreach (KeyValuePair<string, NetworkedPlayerSetting> setting in Settings) { NetworkedPlayerSetting value = setting.Value; if (value.TryGetPayload(out object payload)) { ((Dictionary<object, object>)(object)val).Add((object)setting.Key, payload); } } NetworkedEvent syncEvent = SyncEvent; if (syncEvent != null) { syncEvent.RaiseEvent((object)new object[3] { PlayerID.Local.SteamID, SequenceNumber++, val }, NetworkingEvents.RaiseOthers, SendOptions.SendReliable); } isDirty = false; } public static bool RecieveMessage(EventData e) { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) if (!(e.CustomData is object[] array)) { return false; } if (array.Length != 3) { return false; } if (!(array[0] is string text)) { return false; } PlayerID? playerID = SemiFunc.PlayerAvatarGetFromSteamID(text); if (!playerID.HasValue) { return false; } if (!(array[1] is long seqNum) || 1 == 0) { return false; } object obj = array[2]; Hashtable val = (Hashtable)((obj is Hashtable) ? obj : null); if (val == null) { return false; } DictionaryEntryEnumerator enumerator = val.GetEnumerator(); try { while (((DictionaryEntryEnumerator)(ref enumerator)).MoveNext()) { DictionaryEntry current = ((DictionaryEntryEnumerator)(ref enumerator)).Current; if (current.Key is string key && Settings.TryGetValue(key, out NetworkedPlayerSetting value)) { value.ProcessPayload(playerID.Value, current.Value, seqNum); } } } finally { ((IDisposable)(DictionaryEntryEnumerator)(ref enumerator)).Dispose(); } return true; } } public abstract class NetworkedPlayerSetting { public abstract bool TryGetPayload(out object payload); public abstract bool ProcessPayload(PlayerID playerID, object payload, long seqNum); } public class NetworkedPlayerSetting<T> : NetworkedPlayerSetting { public delegate void OnValueChangedDelegate(PlayerID playerID, T value); protected readonly Dictionary<PlayerID, (T Value, long SequenceNumber)> Values = new Dictionary<PlayerID, (T, long)>(); public event OnValueChangedDelegate? OnValueChanged; public bool TryGetValue(PlayerAvatar avatar, out T value) { value = default(T); PlayerID? playerID = PlayerID.FromAvatar(avatar); if (!playerID.HasValue) { return false; } return TryGetValue(playerID.Value, out value); } public bool TryGetValue(PlayerID playerID, out T value) { if (!Values.TryGetValue(playerID, out (T, long) value2)) { value = default(T); return false; } (value, _) = value2; return true; } private void Set(PlayerID playerID, T value, long seqNum) { Values[playerID] = (value, seqNum); this.OnValueChanged?.Invoke(playerID, value); } public void SetLocalValue(T value) { Set(PlayerID.Local, value, 0L); PlayerSettingSyncer.SetDirty(); } public void BindConfig(ConfigEntry<T> config) { ConfigEntry<T> config2 = config; config2.SettingChanged += delegate { SetLocalValue(config2.Value); }; SetLocalValue(config2.Value); } public override bool TryGetPayload(out object payload) { if (TryGetValue(PlayerID.Local, out var value)) { payload = value; return true; } payload = null; return false; } public override bool ProcessPayload(PlayerID playerID, object payload, long seqNum) { if (Values.TryGetValue(playerID, out (T, long) value) && value.Item2 >= seqNum) { return true; } if (TryDeserializePayload(payload, out var value2)) { Set(playerID, value2, seqNum); return true; } return false; } public virtual bool TryDeserializePayload(object obj, out T value) { if (obj is T val) { value = val; return true; } value = default(T); return false; } } [HarmonyPatch(typeof(PlayerAvatar))] internal static class PlayerAvatarPatches { [HarmonyPostfix] [HarmonyPatch("Awake")] private static void Awake_PostFix() { PlayerSettingSyncer.SetDirty(); } [HarmonyPostfix] [HarmonyPatch("AddToStatsManagerRPC")] private static void AddToStatsManagerRPC_PostFix() { PlayerSettingSyncer.SetDirty(); } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("QueenOfTheLosers", "Queen Of The Losers", "1.1.1")] public class QueenOfTheLosers : BaseUnityPlugin { internal ConfigEntry<string>? TitleConfig; internal ConfigEntry<float>? DeathHeadPitchConfig; internal ConfigEntry<float>? DeathHeadInflectionConfig; internal ConfigEntry<float>? TTSPitchConfig; internal static QueenOfTheLosers Instance { get; private set; } internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; set; } internal void Awake() { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Expected O, but got Unknown //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Expected O, but got Unknown Instance = this; PlayerSettingSyncer.Init(); ((Component)this).transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Patch(); TitleConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Title", "Title Selection", "RULER", new ConfigDescription("A replacement for the title of KING in the \"King of the Losers\" screen", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4] { "QUEEN", "RULER", "KING", "MONARCH" }), Array.Empty<object>())); TitleChange.Init(TitleConfig); DeathHeadPitchConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Death Head Voice", "Pitch", 1f, new ConfigDescription("A modifier for the pitch of your voice while you're possesing your head, Vanilla is 1.0. Note: extreme values can make your voice unintelligible", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.8f, 1.8f), Array.Empty<object>())); DeathHeadInflectionConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Death Head Voice", "Low Battery Inflection", 0.5f, new ConfigDescription("Changes the inflection that is applied when you're running out of battery, Vanilla is 0.5. Note: extreme values can make your voice even more unintelligible", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.4f, 1.8f), Array.Empty<object>())); DeathHeadVoice.Init(DeathHeadPitchConfig, DeathHeadInflectionConfig); TTSPitchConfig = ((BaseUnityPlugin)this).Config.Bind<float>("TTS", "Pitch", 0f, new ConfigDescription("A modifier for the pitch of your TTS voice, Vanilla is 0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.5f, 1f), Array.Empty<object>())); TTSVoicePitch.Init(TTSPitchConfig); Logger.LogMessage((object)TitleChange.ReplaceTitle("KING OF THE LOSERS!", "QUEEN")); } internal void Update() { PlayerSettingSyncer.SendIfDirty(); } internal void Patch() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0026: Expected O, but got Unknown if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Harmony.PatchAll(); } internal void Unpatch() { Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } namespace QueenOfTheLosers.Modifiers { [HarmonyPatch] public static class DeathHeadVoice { [HarmonyPatch] private static class Patches { private static bool CallOverride; [HarmonyPrefix] [HarmonyPatch(typeof(PlayerDeathHead), "Update")] private static void PlayerDeathHead_Update_Prefix(PlayerDeathHead __instance) { CallOverride = __instance.spectated; } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerVoiceChat), "OverridePitch")] private static void PlayerVoiceChat_OverridePitch_Prefix(PlayerVoiceChat __instance, ref float _multiplier) { if (CallOverride && Pitch.TryGetValue(__instance.playerAvatar, out var value) && Inflection.TryGetValue(__instance.playerAvatar, out var value2)) { _multiplier = value * value2; } CallOverride = false; } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerDeathHead), "Update")] private static void PlayerDeathHead_Update_Postfix(PlayerDeathHead __instance) { if (CallOverride && Pitch.TryGetValue(__instance.playerAvatar, out var value)) { CallOverride = false; __instance.playerAvatar.voiceChat.OverridePitch(value, 0.25f, 0.25f, 0.1f, 0f, 0f); } CallOverride = false; } } private static NetworkedPlayerSetting<float>? Pitch; private static NetworkedPlayerSetting<float>? Inflection; public static void Init(ConfigEntry<float> pitch, ConfigEntry<float> inflection) { Pitch = new NetworkedPlayerSetting<float>(); Inflection = new NetworkedPlayerSetting<float>(); PlayerSettingSyncer.RegisterValue("QueenOfTheLosers.DeathHeadVoicePitchSetting", Pitch); PlayerSettingSyncer.RegisterValue("QueenOfTheLosers.DeathHeadVoiceInflectionSetting", Inflection); Pitch.BindConfig(pitch); Inflection.BindConfig(inflection); } } [HarmonyPatch] public class TitleChange : NetworkedPlayerSetting<string> { [HarmonyPatch] private static class Patches { [HarmonyPrefix] [HarmonyPatch(typeof(ArenaMessageWinUI), "ArenaText")] private static void ArenaMessageWinUI_ArenaText_Prefix(ref string? __0, bool __1) { if (__1 && Instance.TryGetValue(SessionManager.instance.CrownedPlayerGet(), out string value)) { __0 = ReplaceTitle(__0, value); } } } public static TitleChange? Instance; public static string ReplaceText = "KING"; public static void Init(ConfigEntry<string> config) { Instance = new TitleChange(); PlayerSettingSyncer.RegisterValue("QueenOfTheLosers.TitleChange", Instance); Instance.BindConfig(config); } public override bool TryDeserializePayload(object obj, out string value) { if (!base.TryDeserializePayload(obj, out value)) { return false; } if (value.Length > 16) { return false; } for (int i = 0; i < value.Length; i++) { if (!char.IsLetterOrDigit(value[i]) && value[i] != ' ') { return false; } } return true; } public static string? ReplaceTitle(string? text, string title) { return text?.Replace(ReplaceText, title, StringComparison.OrdinalIgnoreCase); } } [HarmonyPatch] public static class TTSVoicePitch { [HarmonyPatch] private static class Patches { [HarmonyPostfix] [HarmonyPatch(typeof(TTSVoice), "Start")] private static void TTS_Start_Postfix(TTSVoice __instance) { NetworkedPlayerSetting<float>? pitch = Pitch; if (pitch != null && pitch.TryGetValue(__instance.playerAvatar, out var value)) { __instance.playerAvatar.voiceChat.TTSPitchChange = value; } } } private static NetworkedPlayerSetting<float>? Pitch; public static void Init(ConfigEntry<float> pitch) { Pitch = new NetworkedPlayerSetting<float>(); PlayerSettingSyncer.RegisterValue("QueenOfTheLosers.TTSVoicePitchSetting", Pitch); Pitch.OnValueChanged += delegate(PlayerID playerID, float value) { if ((Object)(object)playerID.Avatar?.voiceChat != (Object)null) { playerID.Avatar.voiceChat.TTSPitchChange = value; } }; Pitch.BindConfig(pitch); } } }