Decompiled source of QueenOfTheLosers v1.1.1

QueenOfTheLosers.dll

Decompiled 2 weeks ago
using 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);
		}
	}
}