Decompiled source of XPScaling v0.2.1

XpScaling.dll

Decompiled 6 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("XpScaling")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+74c389aeb2245b0882a42d9ce0cdde966aad63e9")]
[assembly: AssemblyProduct("XpScaling")]
[assembly: AssemblyTitle("XpScaling")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 XpScaling
{
	internal static class GearGrid
	{
		public static int LargestEmptyRegion(GearData data)
		{
			GearInfo info = data.Gear.Info;
			if (!info.HasUpgradeGrid)
			{
				return 0;
			}
			int width = default(int);
			int height = default(int);
			info.GetUpgradeGridSize(ref width, ref height, false);
			return HexGrid.LargestEmptyRegion(FindOccupiedCells(data, width, height), width, height);
		}

		public static bool[] FindOccupiedCells(GearData data, int width, int height)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			IUpgradable gear = data.Gear;
			bool[] array = new bool[width * height];
			List<UpgradeEquipData> equippedUpgrades = data.equippedUpgrades;
			for (int i = 0; i < (equippedUpgrades?.Count ?? 0); i++)
			{
				UpgradeEquipData val = equippedUpgrades[i];
				UpgradeInstance upgrade = ((UpgradeEquipData)(ref val)).GetUpgrade();
				if (upgrade == null)
				{
					continue;
				}
				EquippedCellsEnumerator equippedCells = upgrade.GetEquippedCells(gear);
				try
				{
					while (((EquippedCellsEnumerator)(ref equippedCells)).MoveNext())
					{
						if (((EquippedCellsEnumerator)(ref equippedCells)).X >= 0 && ((EquippedCellsEnumerator)(ref equippedCells)).X < width && ((EquippedCellsEnumerator)(ref equippedCells)).Y >= 0 && ((EquippedCellsEnumerator)(ref equippedCells)).Y < height)
						{
							array[((EquippedCellsEnumerator)(ref equippedCells)).Y * width + ((EquippedCellsEnumerator)(ref equippedCells)).X] = true;
						}
					}
				}
				finally
				{
					((EquippedCellsEnumerator)(ref equippedCells)).Dispose();
				}
			}
			return array;
		}
	}
	internal static class HexGrid
	{
		private static readonly (int X, int Y)[] EvenColumnNeighbors = new(int, int)[6]
		{
			(0, -1),
			(0, 1),
			(-1, 0),
			(1, 0),
			(-1, -1),
			(1, -1)
		};

		private static readonly (int X, int Y)[] OddColumnNeighbors = new(int, int)[6]
		{
			(0, -1),
			(0, 1),
			(-1, 0),
			(1, 0),
			(-1, 1),
			(1, 1)
		};

		public static int LargestEmptyRegion(bool[] occupied, int width, int height)
		{
			bool[] seen = (bool[])occupied.Clone();
			int num = 0;
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					num = Math.Max(num, Fill(seen, j, i, width, height));
				}
			}
			return num;
		}

		private static int Fill(bool[] seen, int x, int y, int width, int height)
		{
			if (x < 0 || x >= width || y < 0 || y >= height || seen[y * width + x])
			{
				return 0;
			}
			seen[y * width + x] = true;
			int num = 1;
			(int, int)[] array = ((x % 2 == 0) ? EvenColumnNeighbors : OddColumnNeighbors);
			for (int i = 0; i < array.Length; i++)
			{
				(int, int) tuple = array[i];
				int item = tuple.Item1;
				int item2 = tuple.Item2;
				num += Fill(seen, x + item, y + item2, width, height);
			}
			return num;
		}
	}
	[MycoMod(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("xpscaling", "XPScaling", "0.2.1")]
	[BepInProcess("Mycopunk.exe")]
	public class Plugin : BaseUnityPlugin
	{
		private sealed class ItemRecord
		{
			public int? LastRunEmptyRegion;

			public int XpGranted;
		}

		[HarmonyPatch(typeof(GearData), "AddXP")]
		private static class AddXpPatch
		{
			private static void Prefix(GearData __instance, ref int xp)
			{
				if (xp > 0)
				{
					xp = ScaledXp(__instance, xp);
				}
			}

			private static void Postfix(GearData __instance, int xp)
			{
				RecordFor(__instance).XpGranted += xp;
			}
		}

		[HarmonyPatch(typeof(ModuleEquipSlots), "OnEquippedOrUnequipped")]
		private static class GridEditedPatch
		{
			private static void Postfix(ModuleEquipSlots __instance)
			{
				Guarded("could not count an edited grid", delegate
				{
					if (!__instance.skins && __instance.target != null && IsRunInProgress())
					{
						RememberGrid(PlayerData.GetGearData(__instance.target.Info));
					}
				});
			}
		}

		[HarmonyPatch(typeof(MissionManager), "OnNetworkSpawn")]
		private static class MissionStartedPatch
		{
			private static void Postfix()
			{
				items.Clear();
			}
		}

		[HarmonyPatch(typeof(MissionRewardsWindow), "SetRewards")]
		private static class RewardsPatch
		{
			private static void Prefix(List<RewardInfo> rewards)
			{
				Guarded("left rewards unscaled", delegate
				{
					//IL_000b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0010: Unknown result type (might be due to invalid IL or missing references)
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					//IL_004d: Unknown result type (might be due to invalid IL or missing references)
					for (int i = 0; i < rewards.Count; i++)
					{
						RewardInfo val = rewards[i];
						object reward = val.reward;
						IUpgradable val2 = (IUpgradable)((reward is IUpgradable) ? reward : null);
						if (val2 != null && items.TryGetValue(PlayerData.GetGearData(val2.Info), out var value))
						{
							val.amount = value.XpGranted;
							rewards[i] = val;
						}
					}
				});
			}

			private static void Postfix()
			{
				items.Clear();
			}
		}

		private const float StarterCellCount = 25f;

		private const float MaxScalar = 99f;

		private static ManualLogSource Log;

		private static ConfigEntry<float> bonusXpScalar;

		private static ConfigEntry<float> globalXpScalar;

		private static readonly Dictionary<GearData, ItemRecord> items = new Dictionary<GearData, ItemRecord>();

		private void Awake()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			bonusXpScalar = ((BaseUnityPlugin)this).Config.Bind<float>("General", "BonusXpScalar", 1f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 99f), Array.Empty<object>()));
			globalXpScalar = ((BaseUnityPlugin)this).Config.Bind<float>("General", "GlobalXpScalar", 1f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 99f), Array.Empty<object>()));
			UpgradeLookupIndex.Bind(((BaseUnityPlugin)this).Config, Log);
			new Harmony("xpscaling").PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)$"loaded, BonusXpScalar={bonusXpScalar.Value}, GlobalXpScalar={globalXpScalar.Value}");
		}

		private static int ScaleXp(int xp, int emptyRegion, float bonusScalar, float globalScalar)
		{
			return Mathf.RoundToInt((float)xp * globalScalar * (1f + (float)emptyRegion / 25f * bonusScalar));
		}

		private static void Guarded(string failure, Action action)
		{
			try
			{
				action();
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"{failure}: {arg}");
			}
		}

		private static ItemRecord RecordFor(GearData data)
		{
			if (!items.TryGetValue(data, out var value))
			{
				value = new ItemRecord();
				items[data] = value;
			}
			return value;
		}

		private static bool IsRunInProgress()
		{
			MissionManager instance = MissionManager.Instance;
			if ((Object)(object)instance != (Object)null && instance.IsMissionActive)
			{
				return !instance.HasMissionEnded;
			}
			return false;
		}

		private static void RememberGrid(GearData data)
		{
			RecordFor(data).LastRunEmptyRegion = GearGrid.LargestEmptyRegion(data);
		}

		private static int ScaledXp(GearData data, int xp)
		{
			try
			{
				if (IsRunInProgress())
				{
					RememberGrid(data);
				}
				int emptyRegion = RecordFor(data).LastRunEmptyRegion ?? GearGrid.LargestEmptyRegion(data);
				return ScaleXp(xp, emptyRegion, bonusXpScalar.Value, globalXpScalar.Value);
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"left XP unscaled: {arg}");
				return xp;
			}
		}
	}
	internal static class UpgradeLookupIndex
	{
		private readonly struct Slot
		{
			public readonly UpgradeInstance Instance;

			public readonly int Key;

			public readonly int InfoIndex;

			public readonly int InstanceIndex;

			public Slot(UpgradeInstance instance, int key, int infoIndex, int instanceIndex)
			{
				Instance = instance;
				Key = key;
				InfoIndex = infoIndex;
				InstanceIndex = instanceIndex;
			}
		}

		[HarmonyPatch(typeof(PlayerData), "GetUpgradeInstanceFromID", new Type[] { typeof(int) })]
		private static class LookupPatch
		{
			private static bool Prefix(int id, ref UpgradeInstance __result)
			{
				if (!Active)
				{
					return true;
				}
				try
				{
					__result = Find(id);
				}
				catch (Exception e)
				{
					Fault(e);
				}
				return __result == null;
			}

			private static void Postfix(int id, UpgradeInstance __result)
			{
				if (!Active || __result == null || searchOnlyIds.Contains(id))
				{
					return;
				}
				try
				{
					if (Find(id) == null)
					{
						Rebuild();
						if (!slots.ContainsKey(id))
						{
							searchOnlyIds.Add(id);
						}
					}
				}
				catch (Exception e)
				{
					Fault(e);
				}
			}
		}

		private const string Section = "UpgradeLookupIndex";

		private static ManualLogSource log;

		private static ConfigEntry<bool> useIndex;

		private static readonly Dictionary<int, Slot> slots = new Dictionary<int, Slot>();

		private static readonly HashSet<int> searchOnlyIds = new HashSet<int>();

		private static bool faulted;

		private static bool Active
		{
			get
			{
				if (useIndex.Value)
				{
					return !faulted;
				}
				return false;
			}
		}

		internal static void Bind(ConfigFile config, ManualLogSource logger)
		{
			log = logger;
			useIndex = config.Bind<bool>("UpgradeLookupIndex", "Enabled", true, "Use the index for upgrade lookups.");
		}

		private static UpgradeInstance Find(int id)
		{
			Dictionary<int, List<UpgradeInfo>> dictionary = PlayerData.Instance?.data;
			if (dictionary == null || !slots.TryGetValue(id, out var value) || !dictionary.TryGetValue(value.Key, out var value2) || value.InfoIndex >= value2.Count)
			{
				return null;
			}
			List<UpgradeInstance> instances = value2[value.InfoIndex].Instances;
			if (instances == null || value.InstanceIndex >= instances.Count)
			{
				return null;
			}
			UpgradeInstance val = instances[value.InstanceIndex];
			if (val != value.Instance || val.InstanceID != id)
			{
				return null;
			}
			return val;
		}

		private static void Rebuild()
		{
			slots.Clear();
			foreach (KeyValuePair<int, List<UpgradeInfo>> datum in PlayerData.Instance.data)
			{
				for (int i = 0; i < datum.Value.Count; i++)
				{
					List<UpgradeInstance> instances = datum.Value[i].Instances;
					if (instances != null)
					{
						for (int j = 0; j < instances.Count; j++)
						{
							Add(instances[j], datum.Key, i, j);
						}
					}
				}
			}
		}

		private static void Add(UpgradeInstance instance, int key, int infoIndex, int instanceIndex)
		{
			int instanceID = instance.InstanceID;
			if (!searchOnlyIds.Contains(instanceID))
			{
				if (slots.Remove(instanceID))
				{
					searchOnlyIds.Add(instanceID);
				}
				else
				{
					slots[instanceID] = new Slot(instance, key, infoIndex, instanceIndex);
				}
			}
		}

		private static void Fault(Exception e)
		{
			faulted = true;
			log.LogError((object)$"upgrade lookup index turned off: {e}");
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}