Decompiled source of KarmaLocking v1.0.0

KarmaLocking.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HG.Reflection;
using Microsoft.CodeAnalysis;
using On.RoR2;
using On.RoR2.UI;
using RoR2;
using RoR2.Networking;
using RoR2.RemoteGameBrowser;
using RoR2.UI;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("KarmaLocking")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("KarmaLocking")]
[assembly: AssemblyTitle("KarmaLocking")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 KarmaLocking
{
	internal static class KarmaLock
	{
		internal const string KarmaRuleName = "Karma.InitialLevel";

		internal const int Unlocked = -1;

		private static RuleDef karmaRuleDef;

		private static int hostLobbyLevel = -1;

		private static int hostRunLevel = -1;

		private static int receivedLobbyLevel = -1;

		private static int receivedRunLevel = -1;

		internal static bool HostHasMod { get; private set; }

		internal static RuleDef KarmaRuleDef => karmaRuleDef ?? (karmaRuleDef = RuleCatalog.FindRuleDef("Karma.InitialLevel"));

		internal static bool CanLock
		{
			get
			{
				if (!NetworkServer.active)
				{
					return HostHasMod;
				}
				return true;
			}
		}

		internal static int LobbyLevel
		{
			get
			{
				if (!NetworkServer.active)
				{
					if (!HostHasMod)
					{
						return -1;
					}
					return receivedLobbyLevel;
				}
				return hostLobbyLevel;
			}
		}

		internal static int RunLevel
		{
			get
			{
				if (!NetworkServer.active)
				{
					if (!HostHasMod)
					{
						return -1;
					}
					return receivedRunLevel;
				}
				return hostRunLevel;
			}
		}

		internal static bool IsRunLocked
		{
			get
			{
				if (RunLevel >= 0)
				{
					return Object.op_Implicit((Object)(object)Run.instance);
				}
				return false;
			}
		}

		internal static int LevelOf(RuleChoiceDef choiceDef)
		{
			if (choiceDef != null && choiceDef.ruleDef != null && choiceDef.ruleDef == KarmaRuleDef)
			{
				object extraData = choiceDef.extraData;
				if (extraData is int)
				{
					return (int)extraData;
				}
			}
			return -1;
		}

		internal static bool IsKarmaChoice(RuleChoiceDef choiceDef)
		{
			if (choiceDef != null && choiceDef.ruleDef != null)
			{
				return choiceDef.ruleDef == KarmaRuleDef;
			}
			return false;
		}

		internal static bool IsKarmaLevelChoice(RuleChoiceDef choiceDef)
		{
			return LevelOf(choiceDef) >= 0;
		}

		internal static bool IsLobbyLockActive(RuleBook ruleBook)
		{
			int lobbyLevel = LobbyLevel;
			if (lobbyLevel >= 0 && ruleBook != null && KarmaRuleDef != null)
			{
				return LevelOf(ruleBook.GetRuleChoice(KarmaRuleDef)) == lobbyLevel;
			}
			return false;
		}

		internal static bool SetLobbyLevelServer(int level)
		{
			if (!NetworkServer.active)
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)PreGameController.instance))
			{
				KarmaLockingPlugin.Log.LogInfo((object)"Karma can only be locked or unlocked in the lobby.");
				return false;
			}
			if (level < KarmaManager.minKarma || level > KarmaManager.maxKarma)
			{
				level = -1;
			}
			if (hostLobbyLevel != level)
			{
				hostLobbyLevel = level;
				KarmaLockingPlugin.Log.LogInfo((object)((level >= 0) ? $"Karma locked at level {level}." : "Karma unlocked."));
				LockNetwork.BroadcastState();
			}
			return true;
		}

		internal static void OnRunStartServer(Run run)
		{
			if (NetworkServer.active)
			{
				int startingKarma = run.ruleBook.startingKarma;
				hostRunLevel = ((hostLobbyLevel >= 0 && startingKarma == hostLobbyLevel) ? hostLobbyLevel : (-1));
				KarmaLockingPlugin.Log.LogInfo((object)((hostRunLevel >= 0) ? $"Run started with Karma locked at {hostRunLevel}." : $"Run started with Karma unlocked (starting level {startingKarma}, lobby lock {hostLobbyLevel})."));
				LockNetwork.BroadcastState();
			}
		}

		internal static void OnRunDestroyServer()
		{
			if (NetworkServer.active && hostRunLevel != -1)
			{
				hostRunLevel = -1;
				LockNetwork.BroadcastState();
			}
		}

		internal static void GetHostState(out int lobbyLevel, out int runLevel)
		{
			lobbyLevel = hostLobbyLevel;
			runLevel = hostRunLevel;
		}

		internal static void ReceiveState(int lobbyLevel, int runLevel)
		{
			if (!HostHasMod)
			{
				KarmaLockingPlugin.Log.LogInfo((object)"Host has KarmaLocking; Karma can be locked.");
			}
			HostHasMod = true;
			receivedLobbyLevel = lobbyLevel;
			receivedRunLevel = runLevel;
		}

		internal static void ResetClientState()
		{
			HostHasMod = false;
			receivedLobbyLevel = -1;
			receivedRunLevel = -1;
		}

		internal static void RequestLobbyLevel(NetworkUser sender, int level)
		{
			if (NetworkServer.active)
			{
				SetLobbyLevelServer(level);
			}
			else if (HostHasMod && Object.op_Implicit((Object)(object)sender))
			{
				LockNetwork.SendRequest(sender, level);
			}
		}

		internal static NetworkUser NetworkUserForCurrentEventSystem()
		{
			EventSystem current = EventSystem.current;
			EventSystem obj = ((current is MPEventSystem) ? current : null);
			if (obj == null)
			{
				return null;
			}
			LocalUser localUser = ((MPEventSystem)obj).localUser;
			if (localUser == null)
			{
				return null;
			}
			return localUser.currentNetworkUser;
		}
	}
	[BepInPlugin("com.elevated.KarmaLocking", "KarmaLocking", "1.0.0")]
	public class KarmaLockingPlugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Action<Run> <0>__OnRunStartServer;

			public static Action<Run> <1>__Run_onRunDestroyGlobal;

			public static hook_ModifyKarma <2>__KarmaManager_ModifyKarma;

			public static hook_OnClick <3>__RuleChoiceController_OnClick;

			public static hook_SetRandomVotes <4>__RuleCategoryController_SetRandomVotes;

			public static hook_SetChoice <5>__RuleChoiceController_SetChoice;

			public static hook_SetupGridVoteDisplay <6>__RuleCategoryController_SetupGridVoteDisplay;

			public static hook_SetupGridVoteDisplayPopout <7>__RuleCategoryController_SetupGridVoteDisplayPopout;

			public static hook_SetGameInfoInternal <8>__RemoteGameDetailsPanelController_SetGameInfoInternal;

			public static hook_OnEnable <9>__KarmaIcon_OnEnable;

			public static hook_SetDisplayData <10>__GameEndReportPanelController_SetDisplayData;
		}

		public const string PluginGUID = "com.elevated.KarmaLocking";

		public const string PluginName = "KarmaLocking";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> AllowClientLocking;

		private static FieldInfo ruleChoiceDefField;

		private static Func<RuleChoiceDef, bool> setChoiceSource;

		private static bool setChoiceIsVoteButton;

		private static readonly Func<RuleChoiceDef, bool> LobbyButtonSource = delegate(RuleChoiceDef choice)
		{
			int num = KarmaLock.LevelOf(choice);
			return num >= 0 && num == KarmaLock.LobbyLevel;
		};

		private static readonly Func<RuleChoiceDef, bool> NeverLocked = (RuleChoiceDef _) => false;

		public void Awake()
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Expected O, but got Unknown
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Expected O, but got Unknown
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Expected O, but got Unknown
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Expected O, but got Unknown
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			AllowClientLocking = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowClientLocking", true, "Host only. Let other players who have the mod lock and unlock Karma in your lobby. If off, only the host can.");
			LockSprite.Load();
			LockNetwork.Init();
			ruleChoiceDefField = typeof(RuleChoiceController).GetField("choiceDef", BindingFlags.Instance | BindingFlags.NonPublic);
			if (ruleChoiceDefField == null)
			{
				Log.LogError((object)"RuleChoiceController.choiceDef not found; clicking to lock will not work.");
			}
			Run.onRunStartGlobal += KarmaLock.OnRunStartServer;
			Run.onRunDestroyGlobal += Run_onRunDestroyGlobal;
			object obj = <>O.<2>__KarmaManager_ModifyKarma;
			if (obj == null)
			{
				hook_ModifyKarma val = KarmaManager_ModifyKarma;
				<>O.<2>__KarmaManager_ModifyKarma = val;
				obj = (object)val;
			}
			KarmaManager.ModifyKarma += (hook_ModifyKarma)obj;
			object obj2 = <>O.<3>__RuleChoiceController_OnClick;
			if (obj2 == null)
			{
				hook_OnClick val2 = RuleChoiceController_OnClick;
				<>O.<3>__RuleChoiceController_OnClick = val2;
				obj2 = (object)val2;
			}
			RuleChoiceController.OnClick += (hook_OnClick)obj2;
			object obj3 = <>O.<4>__RuleCategoryController_SetRandomVotes;
			if (obj3 == null)
			{
				hook_SetRandomVotes val3 = RuleCategoryController_SetRandomVotes;
				<>O.<4>__RuleCategoryController_SetRandomVotes = val3;
				obj3 = (object)val3;
			}
			RuleCategoryController.SetRandomVotes += (hook_SetRandomVotes)obj3;
			object obj4 = <>O.<5>__RuleChoiceController_SetChoice;
			if (obj4 == null)
			{
				hook_SetChoice val4 = RuleChoiceController_SetChoice;
				<>O.<5>__RuleChoiceController_SetChoice = val4;
				obj4 = (object)val4;
			}
			RuleChoiceController.SetChoice += (hook_SetChoice)obj4;
			object obj5 = <>O.<6>__RuleCategoryController_SetupGridVoteDisplay;
			if (obj5 == null)
			{
				hook_SetupGridVoteDisplay val5 = RuleCategoryController_SetupGridVoteDisplay;
				<>O.<6>__RuleCategoryController_SetupGridVoteDisplay = val5;
				obj5 = (object)val5;
			}
			RuleCategoryController.SetupGridVoteDisplay += (hook_SetupGridVoteDisplay)obj5;
			object obj6 = <>O.<7>__RuleCategoryController_SetupGridVoteDisplayPopout;
			if (obj6 == null)
			{
				hook_SetupGridVoteDisplayPopout val6 = RuleCategoryController_SetupGridVoteDisplayPopout;
				<>O.<7>__RuleCategoryController_SetupGridVoteDisplayPopout = val6;
				obj6 = (object)val6;
			}
			RuleCategoryController.SetupGridVoteDisplayPopout += (hook_SetupGridVoteDisplayPopout)obj6;
			object obj7 = <>O.<8>__RemoteGameDetailsPanelController_SetGameInfoInternal;
			if (obj7 == null)
			{
				hook_SetGameInfoInternal val7 = RemoteGameDetailsPanelController_SetGameInfoInternal;
				<>O.<8>__RemoteGameDetailsPanelController_SetGameInfoInternal = val7;
				obj7 = (object)val7;
			}
			RemoteGameDetailsPanelController.SetGameInfoInternal += (hook_SetGameInfoInternal)obj7;
			object obj8 = <>O.<9>__KarmaIcon_OnEnable;
			if (obj8 == null)
			{
				hook_OnEnable val8 = KarmaIcon_OnEnable;
				<>O.<9>__KarmaIcon_OnEnable = val8;
				obj8 = (object)val8;
			}
			KarmaIcon.OnEnable += (hook_OnEnable)obj8;
			object obj9 = <>O.<10>__GameEndReportPanelController_SetDisplayData;
			if (obj9 == null)
			{
				hook_SetDisplayData val9 = GameEndReportPanelController_SetDisplayData;
				<>O.<10>__GameEndReportPanelController_SetDisplayData = val9;
				obj9 = (object)val9;
			}
			GameEndReportPanelController.SetDisplayData += (hook_SetDisplayData)obj9;
		}

		public void OnDestroy()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Expected O, but got Unknown
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Expected O, but got Unknown
			Run.onRunStartGlobal -= KarmaLock.OnRunStartServer;
			Run.onRunDestroyGlobal -= Run_onRunDestroyGlobal;
			object obj = <>O.<2>__KarmaManager_ModifyKarma;
			if (obj == null)
			{
				hook_ModifyKarma val = KarmaManager_ModifyKarma;
				<>O.<2>__KarmaManager_ModifyKarma = val;
				obj = (object)val;
			}
			KarmaManager.ModifyKarma -= (hook_ModifyKarma)obj;
			object obj2 = <>O.<3>__RuleChoiceController_OnClick;
			if (obj2 == null)
			{
				hook_OnClick val2 = RuleChoiceController_OnClick;
				<>O.<3>__RuleChoiceController_OnClick = val2;
				obj2 = (object)val2;
			}
			RuleChoiceController.OnClick -= (hook_OnClick)obj2;
			object obj3 = <>O.<4>__RuleCategoryController_SetRandomVotes;
			if (obj3 == null)
			{
				hook_SetRandomVotes val3 = RuleCategoryController_SetRandomVotes;
				<>O.<4>__RuleCategoryController_SetRandomVotes = val3;
				obj3 = (object)val3;
			}
			RuleCategoryController.SetRandomVotes -= (hook_SetRandomVotes)obj3;
			object obj4 = <>O.<5>__RuleChoiceController_SetChoice;
			if (obj4 == null)
			{
				hook_SetChoice val4 = RuleChoiceController_SetChoice;
				<>O.<5>__RuleChoiceController_SetChoice = val4;
				obj4 = (object)val4;
			}
			RuleChoiceController.SetChoice -= (hook_SetChoice)obj4;
			object obj5 = <>O.<6>__RuleCategoryController_SetupGridVoteDisplay;
			if (obj5 == null)
			{
				hook_SetupGridVoteDisplay val5 = RuleCategoryController_SetupGridVoteDisplay;
				<>O.<6>__RuleCategoryController_SetupGridVoteDisplay = val5;
				obj5 = (object)val5;
			}
			RuleCategoryController.SetupGridVoteDisplay -= (hook_SetupGridVoteDisplay)obj5;
			object obj6 = <>O.<7>__RuleCategoryController_SetupGridVoteDisplayPopout;
			if (obj6 == null)
			{
				hook_SetupGridVoteDisplayPopout val6 = RuleCategoryController_SetupGridVoteDisplayPopout;
				<>O.<7>__RuleCategoryController_SetupGridVoteDisplayPopout = val6;
				obj6 = (object)val6;
			}
			RuleCategoryController.SetupGridVoteDisplayPopout -= (hook_SetupGridVoteDisplayPopout)obj6;
			object obj7 = <>O.<8>__RemoteGameDetailsPanelController_SetGameInfoInternal;
			if (obj7 == null)
			{
				hook_SetGameInfoInternal val7 = RemoteGameDetailsPanelController_SetGameInfoInternal;
				<>O.<8>__RemoteGameDetailsPanelController_SetGameInfoInternal = val7;
				obj7 = (object)val7;
			}
			RemoteGameDetailsPanelController.SetGameInfoInternal -= (hook_SetGameInfoInternal)obj7;
			object obj8 = <>O.<9>__KarmaIcon_OnEnable;
			if (obj8 == null)
			{
				hook_OnEnable val8 = KarmaIcon_OnEnable;
				<>O.<9>__KarmaIcon_OnEnable = val8;
				obj8 = (object)val8;
			}
			KarmaIcon.OnEnable -= (hook_OnEnable)obj8;
			object obj9 = <>O.<10>__GameEndReportPanelController_SetDisplayData;
			if (obj9 == null)
			{
				hook_SetDisplayData val9 = GameEndReportPanelController_SetDisplayData;
				<>O.<10>__GameEndReportPanelController_SetDisplayData = val9;
				obj9 = (object)val9;
			}
			GameEndReportPanelController.SetDisplayData -= (hook_SetDisplayData)obj9;
		}

		private static void Run_onRunDestroyGlobal(Run run)
		{
			KarmaLock.OnRunDestroyServer();
		}

		private static void KarmaManager_ModifyKarma(orig_ModifyKarma orig, KarmaManager self, int amount)
		{
			if (NetworkServer.active && KarmaLock.IsRunLocked)
			{
				Log.LogDebug((object)$"Karma is locked at {KarmaLock.RunLevel}; ignoring change of {amount}.");
			}
			else
			{
				orig.Invoke(self, amount);
			}
		}

		private static void RuleChoiceController_OnClick(orig_OnClick orig, RuleChoiceController self)
		{
			object? obj = ruleChoiceDefField?.GetValue(self);
			RuleChoiceDef val = (RuleChoiceDef)((obj is RuleChoiceDef) ? obj : null);
			if (!KarmaLock.CanLock || !KarmaLock.IsKarmaChoice(val) || !self.canVote)
			{
				orig.Invoke(self);
				return;
			}
			NetworkUser val2 = KarmaLock.NetworkUserForCurrentEventSystem();
			PreGameRuleVoteController val3 = (Object.op_Implicit((Object)(object)val2) ? PreGameRuleVoteController.FindForUser(val2) : null);
			if (!Object.op_Implicit((Object)(object)val3))
			{
				orig.Invoke(self);
				return;
			}
			int num = KarmaLock.LevelOf(val);
			if (!self.cycleThroughOptions && num >= 0 && val3.IsChoiceVoted(val))
			{
				KarmaLock.RequestLobbyLevel(val2, (KarmaLock.LobbyLevel == num) ? (-1) : num);
				return;
			}
			orig.Invoke(self);
			if (KarmaLock.LobbyLevel >= 0)
			{
				KarmaLock.RequestLobbyLevel(val2, -1);
			}
		}

		private static void RuleCategoryController_SetRandomVotes(orig_SetRandomVotes orig, RuleCategoryController self)
		{
			NetworkUser val = KarmaLock.NetworkUserForCurrentEventSystem();
			PreGameRuleVoteController val2 = (Object.op_Implicit((Object)(object)val) ? PreGameRuleVoteController.FindForUser(val) : null);
			RuleChoiceDef val3 = VotedKarmaChoice(val2);
			orig.Invoke(self);
			if (KarmaLock.LobbyLevel >= 0 && Object.op_Implicit((Object)(object)val2) && VotedKarmaChoice(val2) != val3)
			{
				KarmaLock.RequestLobbyLevel(val, -1);
			}
		}

		private static RuleChoiceDef VotedKarmaChoice(PreGameRuleVoteController voteController)
		{
			if (!Object.op_Implicit((Object)(object)voteController) || KarmaLock.KarmaRuleDef == null)
			{
				return null;
			}
			foreach (RuleChoiceDef choice in KarmaLock.KarmaRuleDef.choices)
			{
				if (voteController.IsChoiceVoted(choice))
				{
					return choice;
				}
			}
			return null;
		}

		private static void RuleChoiceController_SetChoice(orig_SetChoice orig, RuleChoiceController self, RuleChoiceDef newChoiceDef)
		{
			orig.Invoke(self, newChoiceDef);
			RuleChoiceLockBadge ruleChoiceLockBadge = ((Component)self).GetComponent<RuleChoiceLockBadge>();
			if (!Object.op_Implicit((Object)(object)ruleChoiceLockBadge))
			{
				if (!KarmaLock.IsKarmaLevelChoice(newChoiceDef))
				{
					return;
				}
				ruleChoiceLockBadge = RuleChoiceLockBadge.For(self);
			}
			ruleChoiceLockBadge.Choice = newChoiceDef;
			if (setChoiceSource != null)
			{
				ruleChoiceLockBadge.Source = setChoiceSource;
				ruleChoiceLockBadge.ShowClickHint = setChoiceIsVoteButton;
			}
		}

		private static void RuleCategoryController_SetupGridVoteDisplay(orig_SetupGridVoteDisplay orig, RuleCategoryController self, RuleCategoryDef categoryDef, RuleChoiceMask availability, RuleBook ruleBook)
		{
			WithSource((RuleChoiceDef choice) => KarmaLock.IsLobbyLockActive(ruleBook) && ruleBook.GetRuleChoice(KarmaLock.KarmaRuleDef) == choice, isVoteButton: false, delegate
			{
				orig.Invoke(self, categoryDef, availability, ruleBook);
			});
		}

		private static void RuleCategoryController_SetupGridVoteDisplayPopout(orig_SetupGridVoteDisplayPopout orig, RuleCategoryController self, RuleCategoryDef categoryDef, RuleChoiceMask availability, RuleBook ruleBook)
		{
			WithSource(LobbyButtonSource, isVoteButton: true, delegate
			{
				orig.Invoke(self, categoryDef, availability, ruleBook);
			});
		}

		private static void RemoteGameDetailsPanelController_SetGameInfoInternal(orig_SetGameInfoInternal orig, RemoteGameDetailsPanelController self, ref RemoteGameInfo newGameInfo)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			RemoteGameInfo info = newGameInfo;
			WithSource(NeverLocked, isVoteButton: false, delegate
			{
				orig.Invoke(self, ref info);
			});
			newGameInfo = info;
		}

		private static void KarmaIcon_OnEnable(orig_OnEnable orig, KarmaIcon self)
		{
			KarmaIconLockBadge.For(self);
			orig.Invoke(self);
		}

		private static void GameEndReportPanelController_SetDisplayData(orig_SetDisplayData orig, GameEndReportPanelController self, DisplayData newDisplayData)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(self, newDisplayData);
			if (Object.op_Implicit((Object)(object)self.karmaEarnedIcon))
			{
				KarmaIconLockBadge.For(self.karmaEarnedIcon).SetLockedOverride(KarmaLock.IsRunLocked);
			}
		}

		private static void WithSource(Func<RuleChoiceDef, bool> source, bool isVoteButton, Action action)
		{
			Func<RuleChoiceDef, bool> func = setChoiceSource;
			bool flag = setChoiceIsVoteButton;
			setChoiceSource = source;
			setChoiceIsVoteButton = isVoteButton;
			try
			{
				action();
			}
			finally
			{
				setChoiceSource = func;
				setChoiceIsVoteButton = flag;
			}
		}
	}
	internal abstract class LockBadgeBase : MonoBehaviour
	{
		private static readonly Vector2 AnchorMin = new Vector2(0.56f, -0.04f);

		private static readonly Vector2 AnchorMax = new Vector2(1.04f, 0.44f);

		private GameObject badge;

		protected abstract Transform BadgeParent { get; }

		protected abstract bool ShouldShow();

		protected void LateUpdate()
		{
			bool flag;
			try
			{
				flag = ShouldShow();
			}
			catch (Exception ex)
			{
				KarmaLockingPlugin.Log.LogDebug((object)("Lock badge check failed: " + ex.Message));
				flag = false;
			}
			if (flag && !Object.op_Implicit((Object)(object)badge))
			{
				badge = CreateBadge(BadgeParent);
			}
			if (Object.op_Implicit((Object)(object)badge) && badge.activeSelf != flag)
			{
				badge.SetActive(flag);
			}
			OnLateUpdate();
		}

		protected virtual void OnLateUpdate()
		{
		}

		protected void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)badge))
			{
				Object.Destroy((Object)(object)badge);
			}
		}

		private static GameObject CreateBadge(Transform parent)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)parent) || !Object.op_Implicit((Object)(object)LockSprite.Sprite))
			{
				return null;
			}
			GameObject val = new GameObject("KarmaLockBadge", new Type[4]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(LayoutElement)
			})
			{
				layer = ((Component)parent).gameObject.layer
			};
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(parent, false);
			val2.anchorMin = AnchorMin;
			val2.anchorMax = AnchorMax;
			val2.pivot = new Vector2(1f, 0f);
			val2.offsetMin = Vector2.zero;
			val2.offsetMax = Vector2.zero;
			((Transform)val2).SetAsLastSibling();
			val.GetComponent<LayoutElement>().ignoreLayout = true;
			Image component = val.GetComponent<Image>();
			component.sprite = LockSprite.Sprite;
			component.preserveAspect = true;
			((Graphic)component).raycastTarget = false;
			return val;
		}
	}
	internal sealed class RuleChoiceLockBadge : LockBadgeBase
	{
		private RuleChoiceController controller;

		private const string clickHint = "<style=cSub>Click the selected level again to lock Karma at it. Click once more to unlock.</style>";

		internal RuleChoiceDef Choice { get; set; }

		internal Func<RuleChoiceDef, bool> Source { get; set; }

		internal bool ShowClickHint { get; set; }

		protected override Transform BadgeParent
		{
			get
			{
				if (Object.op_Implicit((Object)(object)controller.image))
				{
					return ((Component)controller.image).transform;
				}
				if (!Object.op_Implicit((Object)(object)controller.asyncImage))
				{
					return ((Component)controller).transform;
				}
				return ((Component)controller.asyncImage).transform;
			}
		}

		internal static RuleChoiceLockBadge For(RuleChoiceController controller)
		{
			RuleChoiceLockBadge ruleChoiceLockBadge = ((Component)controller).GetComponent<RuleChoiceLockBadge>();
			if (!Object.op_Implicit((Object)(object)ruleChoiceLockBadge))
			{
				ruleChoiceLockBadge = ((Component)controller).gameObject.AddComponent<RuleChoiceLockBadge>();
				ruleChoiceLockBadge.controller = controller;
			}
			return ruleChoiceLockBadge;
		}

		protected override bool ShouldShow()
		{
			if (!KarmaLock.IsKarmaLevelChoice(Choice))
			{
				return false;
			}
			if (Source == null)
			{
				return IsLockedHere(Choice);
			}
			return Source(Choice);
		}

		private static bool IsLockedHere(RuleChoiceDef choice)
		{
			if (Object.op_Implicit((Object)(object)PreGameController.instance))
			{
				RuleBook readOnlyRuleBook = PreGameController.instance.readOnlyRuleBook;
				if (KarmaLock.IsLobbyLockActive(readOnlyRuleBook))
				{
					return readOnlyRuleBook.GetRuleChoice(KarmaLock.KarmaRuleDef) == choice;
				}
				return false;
			}
			if (KarmaLock.IsRunLocked)
			{
				return KarmaLock.LevelOf(choice) == KarmaLock.RunLevel;
			}
			return false;
		}

		protected override void OnLateUpdate()
		{
			if (ShowClickHint && KarmaLock.CanLock && KarmaLock.IsKarmaLevelChoice(Choice))
			{
				HGButton hgButton = controller.hgButton;
				if (Object.op_Implicit((Object)(object)hgButton) && hgButton.updateTextOnHover && !string.IsNullOrEmpty(hgButton.hoverToken) && !hgButton.hoverToken.EndsWith("<style=cSub>Click the selected level again to lock Karma at it. Click once more to unlock.</style>", StringComparison.Ordinal))
				{
					hgButton.hoverToken += "\n\n<style=cSub>Click the selected level again to lock Karma at it. Click once more to unlock.</style>";
				}
			}
		}
	}
	internal sealed class KarmaIconLockBadge : LockBadgeBase
	{
		private KarmaIcon icon;

		private bool? lockedOverride;

		protected override Transform BadgeParent
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)icon.image))
				{
					return ((Component)icon).transform;
				}
				return ((Component)icon.image).transform;
			}
		}

		internal static KarmaIconLockBadge For(KarmaIcon icon)
		{
			KarmaIconLockBadge karmaIconLockBadge = ((Component)icon).GetComponent<KarmaIconLockBadge>();
			if (!Object.op_Implicit((Object)(object)karmaIconLockBadge))
			{
				karmaIconLockBadge = ((Component)icon).gameObject.AddComponent<KarmaIconLockBadge>();
				karmaIconLockBadge.icon = icon;
			}
			return karmaIconLockBadge;
		}

		internal void SetLockedOverride(bool locked)
		{
			lockedOverride = locked;
		}

		protected override bool ShouldShow()
		{
			return lockedOverride ?? KarmaLock.IsRunLocked;
		}
	}
	internal static class LockNetwork
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static NetworkUserGenericDelegate <0>__OnPostNetworkUserStart;

			public static Action <1>__ResetClientState;
		}

		internal const short StateMessageType = 19276;

		private const byte ProtocolVersion = 1;

		private static readonly HashSet<NetworkConnection> moddedConnections = new HashSet<NetworkConnection>();

		internal static void Init()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			object obj = <>O.<0>__OnPostNetworkUserStart;
			if (obj == null)
			{
				NetworkUserGenericDelegate val = OnPostNetworkUserStart;
				<>O.<0>__OnPostNetworkUserStart = val;
				obj = (object)val;
			}
			NetworkUser.onPostNetworkUserStart += (NetworkUserGenericDelegate)obj;
			NetworkManagerSystem.onStartClientGlobal += delegate
			{
				KarmaLock.ResetClientState();
			};
			NetworkManagerSystem.onStopClientGlobal += KarmaLock.ResetClientState;
			NetworkManagerSystem.onStartServerGlobal += moddedConnections.Clear;
			NetworkManagerSystem.onStopServerGlobal += moddedConnections.Clear;
			NetworkManagerSystem.onServerDisconnectGlobal += delegate(NetworkConnection conn)
			{
				moddedConnections.Remove(conn);
			};
		}

		private static void OnPostNetworkUserStart(NetworkUser networkUser)
		{
			if (!NetworkServer.active && Object.op_Implicit((Object)(object)networkUser) && ((NetworkBehaviour)networkUser).isLocalPlayer)
			{
				Console.instance.SubmitCmd(networkUser, "karmalock_hello", false);
			}
		}

		internal static void SendRequest(NetworkUser sender, int level)
		{
			Console.instance.SubmitCmd(sender, "karmalock_set " + level.ToString(CultureInfo.InvariantCulture), false);
		}

		internal static void BroadcastState()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			moddedConnections.RemoveWhere((NetworkConnection conn) => conn == null || !conn.isConnected);
			foreach (NetworkConnection moddedConnection in moddedConnections)
			{
				SendState(moddedConnection);
			}
		}

		private static void SendState(NetworkConnection conn)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			KarmaLock.GetHostState(out var lobbyLevel, out var runLevel);
			NetworkWriter val = new NetworkWriter();
			val.StartMessage((short)19276);
			val.Write((byte)1);
			val.Write((sbyte)lobbyLevel);
			val.Write((sbyte)runLevel);
			val.FinishMessage();
			conn.SendWriter(val, QosChannelIndex.defaultReliable.intVal);
		}

		private static NetworkConnection RemoteConnectionOf(NetworkUser networkUser)
		{
			if (!Object.op_Implicit((Object)(object)networkUser) || ((NetworkBehaviour)networkUser).isLocalPlayer)
			{
				return null;
			}
			NetworkConnection connectionToClient = ((NetworkBehaviour)networkUser).connectionToClient;
			if (connectionToClient == null || !connectionToClient.isConnected)
			{
				return null;
			}
			return connectionToClient;
		}

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCHello(ConCommandArgs args)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			NetworkConnection val = RemoteConnectionOf(args.sender);
			if (NetworkServer.active && val != null)
			{
				if (moddedConnections.Add(val))
				{
					KarmaLockingPlugin.Log.LogInfo((object)(args.sender.userName + " has KarmaLocking."));
				}
				SendState(val);
			}
		}

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCSet(ConCommandArgs args)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active)
			{
				return;
			}
			((ConCommandArgs)(ref args)).CheckArgumentCount(1);
			int argInt = ((ConCommandArgs)(ref args)).GetArgInt(0);
			if (Object.op_Implicit((Object)(object)args.sender) && !((NetworkBehaviour)args.sender).isLocalPlayer && !KarmaLockingPlugin.AllowClientLocking.Value)
			{
				KarmaLockingPlugin.Log.LogInfo((object)("Ignored Karma lock request from " + args.sender.userName + " (AllowClientLocking is off)."));
				NetworkConnection val = RemoteConnectionOf(args.sender);
				if (val != null && moddedConnections.Contains(val))
				{
					SendState(val);
				}
			}
			else
			{
				KarmaLock.SetLobbyLevelServer(argInt);
			}
		}

		[NetworkMessageHandler(msgType = 19276, client = true)]
		private static void HandleState(NetworkMessage netMsg)
		{
			if (!NetworkServer.active)
			{
				byte b = netMsg.reader.ReadByte();
				if (b != 1)
				{
					KarmaLockingPlugin.Log.LogWarning((object)$"Host uses a different KarmaLocking protocol ({b}, expected {(byte)1}); update the mod.");
					return;
				}
				sbyte lobbyLevel = netMsg.reader.ReadSByte();
				int runLevel = netMsg.reader.ReadSByte();
				KarmaLock.ReceiveState(lobbyLevel, runLevel);
			}
		}

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCStatus(ConCommandArgs args)
		{
			string arg = (NetworkServer.active ? "host" : (NetworkClient.active ? "client" : "offline"));
			int num = (Object.op_Implicit((Object)(object)KarmaManager.instance) ? KarmaManager.instance.GetEffectiveKarma() : (-1));
			Debug.Log((object)($"[KarmaLocking] role={arg} canLock={KarmaLock.CanLock} hostHasMod={KarmaLock.HostHasMod} " + $"lobbyLevel={KarmaLock.LobbyLevel} runLevel={KarmaLock.RunLevel} currentKarma={num} moddedClients={moddedConnections.Count}"));
		}
	}
	internal static class LockSprite
	{
		internal static Sprite Sprite { get; private set; }

		internal static void Load()
		{
			Sprite = LoadSprite("KarmaLocking.lock.png", "texKarmaLock");
		}

		private static Sprite LoadSprite(string resourceName, string name)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			using Stream stream = typeof(LockSprite).Assembly.GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				KarmaLockingPlugin.Log.LogError((object)("Embedded resource '" + resourceName + "' is missing."));
				return null;
			}
			byte[] array = new byte[stream.Length];
			using (MemoryStream destination = new MemoryStream(array))
			{
				stream.CopyTo(destination);
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
			{
				name = name,
				wrapMode = (TextureWrapMode)1,
				filterMode = (FilterMode)1
			};
			if (!ImageConversion.LoadImage(val, array))
			{
				KarmaLockingPlugin.Log.LogError((object)("Could not decode '" + resourceName + "'."));
				return null;
			}
			Object.DontDestroyOnLoad((Object)(object)val);
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			((Object)obj).name = name;
			Object.DontDestroyOnLoad((Object)(object)obj);
			return obj;
		}
	}
}