Decompiled source of MySix ForgeOfPotential v1.0.3

MySix.ForgeOfPotential.dll

Decompiled an hour ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using HarmonyLib;
using MySix.Core;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace MySix
{
	internal static class SuiteVersion
	{
		public const string Value = "1.0.3";
	}
}
namespace MySix.ForgeOfPotential
{
	public enum ForgeMode
	{
		Vanilla,
		NeverBreak,
		Gamble
	}
	public static class ForgeHooks
	{
		public static Setting<ForgeMode> Mode;

		public static Setting<float> FailChance;

		public static Setting<bool> FailureEffect;

		public static Setting<bool> LogOutcomes;

		private static readonly EffectList NoEffects = new EffectList();

		private static float _vanillaUpgradeChance;

		private static float _breakChance;

		private static readonly FieldRef<InventoryGui, Recipe> CraftRecipe = AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe");

		public static float UpgradeChance(float vanilla)
		{
			_vanillaUpgradeChance = vanilla;
			if (Mode.Value == ForgeMode.Vanilla)
			{
				return vanilla;
			}
			float num = ((FailChance != null) ? Mathf.Clamp01(FailChance.Value) : 0.35f);
			return 1f - num;
		}

		public static float BreakChance(float vanilla)
		{
			_breakChance = vanilla;
			if (Mode.Value != ForgeMode.Vanilla)
			{
				return 0f;
			}
			return vanilla;
		}

		public static EffectList FailEffects(EffectList vanilla)
		{
			if (Mode.Value == ForgeMode.Vanilla)
			{
				return vanilla;
			}
			if (FailureEffect != null && FailureEffect.Value)
			{
				return vanilla;
			}
			return NoEffects;
		}

		public static string FailedMessage()
		{
			return Mode.Value switch
			{
				ForgeMode.NeverBreak => "The idol crumbles and nothing comes of it. {0} is unharmed.", 
				ForgeMode.Gamble => "The idol crumbles and {0} is weakened, down to level {1}.", 
				_ => "$msg_upgrader_failed", 
			};
		}

		public static int FailedLevel(int targetLevel)
		{
			int num = targetLevel + ((Mode.Value == ForgeMode.NeverBreak) ? (-1) : (-2));
			num = Mathf.Max(1, num);
			if (LogOutcomes != null && LogOutcomes.Value)
			{
				CorePlugin.Log.LogInfo((object)($"ForgeOfPotential [{Mode.Value}]: target level {targetLevel}, the game " + $"would have rolled upgrade {_vanillaUpgradeChance:0.###} / break " + $"{_breakChance:0.###}, handing back level {num}"));
			}
			return num;
		}

		private static int MaxQuality()
		{
			try
			{
				if ((Object)(object)InventoryGui.instance == (Object)null)
				{
					return 0;
				}
				ItemDrop val = CraftRecipe.Invoke(InventoryGui.instance)?.m_item;
				return ((Object)(object)val != (Object)null) ? val.m_itemData.m_shared.m_maxQuality : 0;
			}
			catch
			{
				return 0;
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
	public static class DoCraftingPatch
	{
		private static readonly FieldInfo UpgradeChanceField = AccessTools.Field(typeof(SharedData), "m_upgradeChance");

		private static readonly FieldInfo BreakChanceField = AccessTools.Field(typeof(SharedData), "m_breakChance");

		private static readonly FieldInfo FailEffectsField = AccessTools.Field(typeof(CraftingStation), "m_craftItemDoneFailEffects");

		private static readonly MethodInfo AddItem = AccessTools.Method(typeof(Inventory), "AddItem", new Type[10]
		{
			typeof(string),
			typeof(int),
			typeof(int),
			typeof(int),
			typeof(long),
			typeof(string),
			typeof(Vector2i),
			typeof(bool),
			typeof(bool),
			typeof(bool)
		}, (Type[])null);

		public static bool Applied { get; private set; }

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Expected O, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Expected O, but got Unknown
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Expected O, but got Unknown
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			for (int i = 0; i < list.Count; i++)
			{
				if (!(list[i].opcode != OpCodes.Ldfld))
				{
					if (list[i].operand == UpgradeChanceField || object.Equals(list[i].operand, UpgradeChanceField))
					{
						list.Insert(++i, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ForgeHooks), "UpgradeChance", (Type[])null, (Type[])null)));
						num++;
					}
					else if (list[i].operand == BreakChanceField || object.Equals(list[i].operand, BreakChanceField))
					{
						list.Insert(++i, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ForgeHooks), "BreakChance", (Type[])null, (Type[])null)));
						num++;
					}
				}
			}
			for (int j = 0; j < list.Count; j++)
			{
				if (list[j].opcode == OpCodes.Ldstr && (string)list[j].operand == "$msg_upgrader_failed")
				{
					list[j] = new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ForgeHooks), "FailedMessage", (Type[])null, (Type[])null))
					{
						labels = list[j].labels,
						blocks = list[j].blocks
					};
					num2++;
					break;
				}
			}
			for (int k = 0; k < list.Count; k++)
			{
				if (!(list[k].opcode == OpCodes.Callvirt) || !object.Equals(list[k].operand, AddItem))
				{
					continue;
				}
				int num4 = k - 1;
				while (num4 > k - 20 && num4 > 1)
				{
					if (list[num4].opcode == OpCodes.Sub && CodeInstructionExtensions.LoadsConstant(list[num4 - 1], 2L) && CodeInstructionExtensions.IsLdloc(list[num4 - 2], (LocalBuilder)null))
					{
						list[num4 - 1] = new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ForgeHooks), "FailedLevel", (Type[])null, (Type[])null));
						list.RemoveAt(num4);
						num3++;
						break;
					}
					num4--;
				}
				if (num3 > 0)
				{
					break;
				}
			}
			int num5 = 0;
			for (int l = 0; l < list.Count; l++)
			{
				if (list[l].opcode == OpCodes.Ldfld && object.Equals(list[l].operand, FailEffectsField))
				{
					list.Insert(++l, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ForgeHooks), "FailEffects", (Type[])null, (Type[])null)));
					num5++;
				}
			}
			if (num5 != 1)
			{
				CorePlugin.Log.LogWarning((object)($"ForgeOfPotential hooked {num5} failure effect sites, expected 1; " + "a failed refinement may still set off the forge blast."));
			}
			if (num == 2 && num2 == 1 && num3 == 1)
			{
				Applied = true;
				return list;
			}
			CorePlugin.Log.LogError((object)($"ForgeOfPotential could not patch DoCrafting (chance hooks {num}/2, " + $"message {num2}/1, level {num3}/1). The game may have changed; " + "the Forge of Potential will behave normally."));
			return instructions;
		}
	}
	[BepInPlugin("com.mysix.forgeofpotential", "MySix Forge of Potential", "1.0.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class ForgeOfPotentialPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.mysix.forgeofpotential";

		public const string PluginName = "MySix Forge of Potential";

		public const string PluginVersion = "1.0.3";

		private const int RequiredCoreApi = 1;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			if (CorePlugin.RequireApi("MySix Forge of Potential", 1))
			{
				ForgeHooks.Mode = Settings.Register<ForgeMode>("MySix Forge of Potential", ((BaseUnityPlugin)this).Config.Bind<ForgeMode>("ForgeOfPotential", "Mode", ForgeMode.NeverBreak, "Vanilla: unchanged, so a failed refinement destroys the item. NeverBreak: the idol is used up, but a failure costs nothing else. Gamble: as NeverBreak, except a failure also takes the item down one level. Neither modified mode ever destroys the item."), (Scope)0, (string)null);
				ForgeHooks.FailChance = Settings.Register<float>("MySix Forge of Potential", ((BaseUnityPlugin)this).Config.Bind<float>("ForgeOfPotential", "FailChance", 0.35f, "Chance a refinement does not take, in NeverBreak and Gamble. 0.35 matches the odds the game itself uses, so a success is still the usual one level of upgrade 65% of the time."), (Scope)0, (string)null);
				ForgeHooks.FailureEffect = Settings.Register<bool>("MySix Forge of Potential", ((BaseUnityPlugin)this).Config.Bind<bool>("ForgeOfPotential", "FailureEffect", false, "Play the station's own failure effect when a refinement does not take. It is only for show and harms nothing, but it looks like a disaster, so it is off by default in modes where the gear survives."), (Scope)0, (string)null);
				ForgeHooks.LogOutcomes = Settings.Register<bool>("MySix Forge of Potential", ((BaseUnityPlugin)this).Config.Bind<bool>("ForgeOfPotential", "LogOutcomes", false, "Log every upgrade outcome, for checking the odds behave as expected."), (Scope)1, (string)null);
				_harmony = new Harmony("com.mysix.forgeofpotential");
				_harmony.PatchAll(typeof(ForgeOfPotentialPlugin).Assembly);
				((BaseUnityPlugin)this).Logger.LogInfo((object)(string.Format("{0} {1} loaded; mode {2}, ", "MySix Forge of Potential", "1.0.3", ForgeHooks.Mode.Value) + "patch " + (DoCraftingPatch.Applied ? "applied" : "NOT applied")));
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}