Decompiled source of QuotaMoonUnlocker v0.0.1

QuotaMoonUnlocker.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dawn;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MoonProgression.Helpers;
using MoonProgression.Main;
using MoonProgression.Patches;
using QuotaMoonUnlocker.NetcodePatcher;
using Unity.Collections;
using Unity.Netcode;
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("QuotaMoonUnlocker")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: AssemblyInformationalVersion("0.0.1")]
[assembly: AssemblyProduct("QuotaMoonUnlocker")]
[assembly: AssemblyTitle("QuotaMoonUnlocker")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 MoonProgression
{
	[BepInPlugin("MrHat.QuotaMoonUnlocker", "QuotaMoonUnlocker", "0.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal const string modGUID = "MrHat.QuotaMoonUnlocker";

		internal const string modName = "QuotaMoonUnlocker";

		internal const string modVersion = "0.0.1";

		internal static Harmony _harmony;

		internal static ManualLogSource mls;

		internal static Plugin Instance;

		internal static ConfigEntry<bool> DebugEnabled { get; private set; }

		internal static ConfigEntry<string> UnlockPlan { get; private set; }

		private void Awake()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			Instance = this;
			mls = Logger.CreateLogSource("MrHat.QuotaMoonUnlocker");
			_harmony = new Harmony("MrHat.QuotaMoonUnlocker");
			DebugEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Enabled", false, "Enables debug logging.");
			UnlockPlan = ((BaseUnityPlugin)this).Config.Bind<string>("Moon Unlocking", "Unlock Plan", "0:Experimentation;Assurance,1:Vow;Offense,2:March;Rend;Dine,4:Titan", "Format: QuotaCount:Moon1;Moon3,QuotaCount:Moon2");
			MoonUnlocker.UpdateConfig(UnlockPlan.Value);
			_harmony.PatchAll(typeof(HarmonyPatches));
		}

		internal static void LogDebug(string message)
		{
			if (DebugEnabled.Value)
			{
				mls.LogDebug((object)message);
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "QuotaMoonUnlocker";

		public const string PLUGIN_NAME = "QuotaMoonUnlocker";

		public const string PLUGIN_VERSION = "0.0.1";
	}
}
namespace MoonProgression.Patches
{
	internal static class HarmonyPatches
	{
		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		[HarmonyPrefix]
		private static void StartOfRoundAwakePrefix()
		{
			MoonUnlocker.EnsureQuotaMessageRegistered();
		}

		[HarmonyPatch(typeof(StartOfRound), "Start")]
		[HarmonyPostfix]
		private static void StartOfRoundStartPostfix()
		{
			MoonUnlocker.ApplyPredicatesToAllLevels();
			if (((NetworkBehaviour)StartOfRound.Instance).IsServer)
			{
				MoonUnlocker.BroadcastQuota();
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "PlayerLoadedServerRpc")]
		[HarmonyPostfix]
		private static void PlayerLoadedServerRpcPostfix(ulong clientId)
		{
			if (((NetworkBehaviour)StartOfRound.Instance).IsServer)
			{
				MoonUnlocker.SyncQuota(clientId);
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "OnDestroy")]
		[HarmonyPostfix]
		private static void StartOfRoundOnDestroyPostfix()
		{
			MoonUnlocker.ResetQuotaSync();
		}

		[HarmonyPatch(typeof(TimeOfDay), "SetNewProfitQuota")]
		[HarmonyPostfix]
		private static void SetNewProfitQuotaPostfix()
		{
			MoonUnlocker.OnNewQuotaSet();
		}
	}
}
namespace MoonProgression.Main
{
	internal static class MoonUnlocker
	{
		private readonly struct UnlockGroup
		{
			public readonly int RequiredCompletedQuotas;

			public readonly string[] Moons;

			public UnlockGroup(int requiredCompletedQuotas, string[] moons)
			{
				RequiredCompletedQuotas = requiredCompletedQuotas;
				Moons = moons;
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnQuotaSyncMessage;
		}

		private static readonly Dictionary<string, int> moonUnlockQuotaByKey = new Dictionary<string, int>();

		private static readonly Dictionary<string, string> originalMoonNameByKey = new Dictionary<string, string>();

		private const string QuotaSyncMessage = "MrHat.QuotaMoonUnlocker.Sync";

		private static NetworkManager registeredNetworkManager;

		private static readonly bool quotaMessageRegistered;

		private static int syncedCompletedQuotas = -1;

		private static int lastSeenCompletedQuotas = 0;

		private static bool loggedInitialSync;

		internal static void UpdateConfig(string unlockPlanText)
		{
			moonUnlockQuotaByKey.Clear();
			originalMoonNameByKey.Clear();
			List<UnlockGroup> list = ParseUnlockPlan(unlockPlanText);
			foreach (UnlockGroup item in list)
			{
				string[] moons = item.Moons;
				foreach (string text in moons)
				{
					string key = NormaliseKey(text);
					if (moonUnlockQuotaByKey.TryGetValue(key, out var value))
					{
						if (item.RequiredCompletedQuotas < value)
						{
							moonUnlockQuotaByKey[key] = item.RequiredCompletedQuotas;
						}
					}
					else
					{
						moonUnlockQuotaByKey[key] = item.RequiredCompletedQuotas;
						originalMoonNameByKey[key] = text;
					}
				}
			}
			Plugin.LogDebug($"Unlock plan entries: {moonUnlockQuotaByKey.Count}");
		}

		internal static void ApplyPredicatesToAllLevels()
		{
			SelectableLevel[] levels = StartOfRound.Instance.levels;
			int num = 0;
			SelectableLevel[] array = levels;
			foreach (SelectableLevel val in array)
			{
				string key = NormaliseKey(val.PlanetName);
				if (moonUnlockQuotaByKey.TryGetValue(key, out var value))
				{
					DawnMoonInfo dawnInfo = DawnHelper.GetDawnInfo(val);
					DawnPurchaseInfo dawnPurchaseInfo = dawnInfo.DawnPurchaseInfo;
					ITerminalPurchasePredicate purchasePredicate = dawnPurchaseInfo.PurchasePredicate;
					if (!(purchasePredicate is QuotaUnlockPredicate))
					{
						string planetName = val.PlanetName;
						QuotaUnlockPredicate predicate = new QuotaUnlockPredicate(val.PlanetName, purchasePredicate, value);
						DawnHelper.SetPurchasePredicate(dawnPurchaseInfo, (ITerminalPurchasePredicate)(object)predicate);
						num++;
					}
				}
			}
			Plugin.LogDebug($"Applied predicates: {num}");
		}

		internal static void OnNewQuotaSet()
		{
			int timesFulfilledQuota = TimeOfDay.Instance.timesFulfilledQuota;
			if (!NetworkManager.Singleton.IsServer && syncedCompletedQuotas >= 0 && timesFulfilledQuota > syncedCompletedQuotas)
			{
				syncedCompletedQuotas = timesFulfilledQuota;
			}
			if (timesFulfilledQuota != lastSeenCompletedQuotas)
			{
				lastSeenCompletedQuotas = timesFulfilledQuota;
				Plugin.LogDebug($"Quota now: {timesFulfilledQuota}");
				if (((NetworkBehaviour)StartOfRound.Instance).IsServer)
				{
					BroadcastQuota();
				}
			}
		}

		internal static void EnsureQuotaMessageRegistered()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			NetworkManager singleton = NetworkManager.Singleton;
			if (!((Object)(object)singleton == (Object)null) && !((Object)(object)registeredNetworkManager == (Object)(object)singleton))
			{
				NetworkManager obj = registeredNetworkManager;
				if (obj != null)
				{
					obj.CustomMessagingManager.UnregisterNamedMessageHandler("MrHat.QuotaMoonUnlocker.Sync");
				}
				registeredNetworkManager = singleton;
				CustomMessagingManager customMessagingManager = registeredNetworkManager.CustomMessagingManager;
				object obj2 = <>O.<0>__OnQuotaSyncMessage;
				if (obj2 == null)
				{
					HandleNamedMessageDelegate val = OnQuotaSyncMessage;
					<>O.<0>__OnQuotaSyncMessage = val;
					obj2 = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler("MrHat.QuotaMoonUnlocker.Sync", (HandleNamedMessageDelegate)obj2);
			}
		}

		private static void OnQuotaSyncMessage(ulong senderClientId, FastBufferReader reader)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			if (num > syncedCompletedQuotas)
			{
				syncedCompletedQuotas = num;
			}
			if (!loggedInitialSync)
			{
				loggedInitialSync = true;
				Plugin.LogDebug($"Synced quota from host: {syncedCompletedQuotas}");
			}
		}

		internal static int GetCompletedQuotas()
		{
			if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer)
			{
				return TimeOfDay.Instance.timesFulfilledQuota;
			}
			if (syncedCompletedQuotas >= 0)
			{
				return syncedCompletedQuotas;
			}
			return ((Object)(object)TimeOfDay.Instance != (Object)null) ? TimeOfDay.Instance.timesFulfilledQuota : 0;
		}

		internal static void SyncQuota(ulong clientId)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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)
			if (!NetworkManager.Singleton.IsServer)
			{
				return;
			}
			EnsureQuotaMessageRegistered();
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref TimeOfDay.Instance.timesFulfilledQuota, default(ForPrimitives));
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("MrHat.QuotaMoonUnlocker.Sync", clientId, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref val)).Dispose();
			}
		}

		internal static void BroadcastQuota()
		{
			if (NetworkManager.Singleton.IsServer)
			{
				IReadOnlyList<ulong> connectedClientsIds = NetworkManager.Singleton.ConnectedClientsIds;
				for (int i = 0; i < connectedClientsIds.Count; i++)
				{
					SyncQuota(connectedClientsIds[i]);
				}
			}
		}

		internal static void ResetQuotaSync()
		{
			syncedCompletedQuotas = -1;
			lastSeenCompletedQuotas = 0;
			loggedInitialSync = false;
			registeredNetworkManager = null;
		}

		private static string NormaliseKey(string raw)
		{
			StringBuilder stringBuilder = new StringBuilder(raw.Length);
			foreach (char c in raw)
			{
				if (char.IsLetter(c))
				{
					stringBuilder.Append(char.ToUpperInvariant(c));
				}
			}
			return stringBuilder.ToString();
		}

		private static List<UnlockGroup> ParseUnlockPlan(string text)
		{
			List<UnlockGroup> list = new List<UnlockGroup>();
			if (string.IsNullOrWhiteSpace(text))
			{
				return list;
			}
			int num = text.IndexOf(':');
			if (num < 0)
			{
				return list;
			}
			int num2 = text.IndexOf(',', num + 1);
			int num3 = text.IndexOf(';', num + 1);
			bool flag = num3 != -1 && (num2 == -1 || num3 < num2);
			char c = (flag ? ',' : ';');
			char c2 = (flag ? ';' : ',');
			string[] array = text.Split(new char[1] { c }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text2 in array2)
			{
				string[] array3 = text2.Split(new char[1] { ':' }, 2);
				if (array3.Length == 2 && int.TryParse(array3[0].Trim(), out var result))
				{
					string[] array4 = (from m in array3[1].Split(new char[1] { c2 }, StringSplitOptions.RemoveEmptyEntries)
						select m.Trim() into m
						where m.Length > 0
						select m).ToArray();
					if (array4.Length != 0)
					{
						list.Add(new UnlockGroup(result, array4));
					}
				}
			}
			return list;
		}
	}
	internal sealed class QuotaUnlockPredicate : ITerminalPurchasePredicate
	{
		private readonly string moonNameForLogs;

		private readonly ITerminalPurchasePredicate basePredicate;

		private readonly int requiredCompletedQuotas;

		private readonly TerminalNode lockedNode;

		private int lastSeenQuotas = 0;

		private bool lastSeenUnlocked;

		internal QuotaUnlockPredicate(string moonNameForLogs, ITerminalPurchasePredicate basePredicate, int requiredCompletedQuotas)
		{
			this.moonNameForLogs = moonNameForLogs;
			this.basePredicate = basePredicate;
			this.requiredCompletedQuotas = requiredCompletedQuotas;
			lockedNode = ScriptableObject.CreateInstance<TerminalNode>();
			lockedNode.clearPreviousText = true;
		}

		private static string BuildLockedText(int requiredQuota, int currentQuota)
		{
			return $"This moon is locked until quota {requiredQuota}, you are currently on quota {currentQuota}. Back to work, you slacker!";
		}

		public TerminalPurchaseResult CanPurchase()
		{
			TerminalPurchaseResult val = basePredicate.CanPurchase();
			if (val is HiddenPurchaseResult)
			{
				return val;
			}
			if (val is FailedPurchaseResult)
			{
				return val;
			}
			int completedQuotas = MoonUnlocker.GetCompletedQuotas();
			bool flag = completedQuotas >= requiredCompletedQuotas;
			if (completedQuotas != lastSeenQuotas || flag != lastSeenUnlocked)
			{
				Plugin.LogDebug($"Predicate check '{moonNameForLogs}': CompletedQuotas={completedQuotas}, Required={requiredCompletedQuotas}, Unlocked={flag}");
				lastSeenQuotas = completedQuotas;
				lastSeenUnlocked = flag;
			}
			if (flag)
			{
				return (TerminalPurchaseResult)(object)TerminalPurchaseResult.Success();
			}
			lockedNode.displayText = BuildLockedText(requiredCompletedQuotas, completedQuotas);
			HiddenPurchaseResult val2 = TerminalPurchaseResult.Hidden();
			val2.SetFailure(true);
			val2.SetFailNode(lockedNode);
			return (TerminalPurchaseResult)(object)val2;
		}
	}
}
namespace MoonProgression.Helpers
{
	internal static class DawnHelper
	{
		private static readonly MethodInfo setPurchasePredicate = AccessTools.PropertySetter(typeof(DawnPurchaseInfo), "PurchasePredicate");

		private static bool reportedMissingSetter;

		internal static DawnMoonInfo GetDawnInfo(SelectableLevel level)
		{
			return SelectableLevelExtensions.GetDawnInfo(level);
		}

		internal static bool SetPurchasePredicate(DawnPurchaseInfo purchaseInfo, ITerminalPurchasePredicate predicate)
		{
			if (setPurchasePredicate == null)
			{
				if (!reportedMissingSetter)
				{
					reportedMissingSetter = true;
					Plugin.LogDebug("DawnHelper: PurchasePredicate setter not found. Predicate cannot be replaced.");
				}
				return false;
			}
			setPurchasePredicate.Invoke(purchaseInfo, new object[1] { predicate });
			return true;
		}
	}
}
namespace __GEN
{
	internal class NetworkVariableSerializationHelper
	{
		[RuntimeInitializeOnLoadMethod]
		internal static void InitializeSerialization()
		{
		}
	}
}
namespace QuotaMoonUnlocker.NetcodePatcher
{
	[AttributeUsage(AttributeTargets.Module)]
	internal class NetcodePatchedAssemblyAttribute : Attribute
	{
	}
}