Decompiled source of Shack Blast Furnace Ascended v1.0.0

ShackBlastFurnace.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ShackBlastFurnace")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ShackBlastFurnace")]
[assembly: AssemblyTitle("ShackBlastFurnace")]
[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 TheShack.BlastFurnace
{
	[BepInPlugin("theshack.blastfurnace", "Shack Blast Furnace Ascended", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "theshack.blastfurnace";

		public const string PluginName = "Shack Blast Furnace Ascended";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Settings.Bind(((BaseUnityPlugin)this).Config);
			if (!Furnaces.Ready)
			{
				Log.LogError((object)"Shack Blast Furnace Ascended can't find Smelter.GetQueuedOre in this game version; the blast furnace stays as the game has it.");
				return;
			}
			Harmony val = new Harmony("theshack.blastfurnace");
			try
			{
				val.PatchAll(Assembly.GetExecutingAssembly());
			}
			catch (Exception arg)
			{
				val.UnpatchSelf();
				Log.LogError((object)string.Format("{0} could not hook into this game version; the blast furnace stays as the game has it. {1}", "Shack Blast Furnace Ascended", arg));
				return;
			}
			((BaseUnityPlugin)this).Config.SettingChanged += delegate
			{
				Furnaces.ApplyToLoaded();
			};
			SynchronizationManager.OnConfigurationSynchronized += delegate
			{
				Furnaces.ApplyToLoaded();
			};
			Log.LogInfo((object)string.Format("{0} {1} ready ({2:0.##}x speed, {3:0.##}x coal).", "Shack Blast Furnace Ascended", "1.0.0", Settings.Speed.Value, Settings.Coal.Value));
		}
	}
	internal static class Settings
	{
		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<float> Speed;

		public static ConfigEntry<float> Coal;

		public static ConfigEntry<int> OreCapacity;

		public static ConfigEntry<int> CoalCapacity;

		public static readonly Dictionary<string, ConfigEntry<bool>> Ores = new Dictionary<string, ConfigEntry<bool>>();

		public static void Bind(ConfigFile config)
		{
			int order = 100;
			Enabled = Bind<bool>("1 - General", "Enabled", value: true, "The blast furnace takes the ores ticked under \"2 - Ores\" and smelts them at the speed below. Off: the blast furnace works as in the base game (any of those ores already in it still finish).");
			Speed = Bind<float>("1 - General", "Speed", 4f, "How many times faster than the regular furnace the blast furnace smelts those ores. 4 = four times as fast; 1 = as slow as the regular furnace.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f));
			Coal = Bind<float>("1 - General", "Coal per ore", 1f, "Coal those ores burn, compared with the regular furnace. 1 = the same coal per ore (it just burns faster), 0.5 = half, 0 = none (it still needs some coal in it to run).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f));
			OreCapacity = Bind<int>("1 - General", "Ore capacity", 0, "How much ore the blast furnace holds, all kinds together (black metal and flametal too). 0 = the game's own.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100));
			CoalCapacity = Bind<int>("1 - General", "Coal capacity", 0, "How much coal the blast furnace holds. 0 = the game's own.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200));
			Ores["CopperOre"] = Bind<bool>("2 - Ores", "Copper ore", value: true, "The blast furnace smelts copper ore into copper.");
			Ores["TinOre"] = Bind<bool>("2 - Ores", "Tin ore", value: true, "The blast furnace smelts tin ore into tin.");
			Ores["IronScrap"] = Bind<bool>("2 - Ores", "Scrap iron", value: true, "The blast furnace smelts scrap iron into iron.");
			Ores["SilverOre"] = Bind<bool>("2 - Ores", "Silver ore", value: true, "The blast furnace smelts silver ore into silver.");
			ConfigEntry<T> Bind<T>(string section, string key, T value, string description, AcceptableValueBase range = null)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Expected O, but got Unknown
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Expected O, but got Unknown
				return config.Bind<T>(section, key, value, new ConfigDescription(description, range, new object[1] { (object)new ConfigurationManagerAttributes
				{
					IsAdminOnly = true,
					Order = order--
				} }));
			}
		}
	}
	internal static class Furnaces
	{
		private const string BlastFurnaceName = "$piece_blastfurnace";

		private static readonly MethodInfo GetQueuedOre = AccessTools.Method(typeof(Smelter), "GetQueuedOre", (Type[])null, (Type[])null);

		private static readonly Func<Smelter, string> QueuedOre = ((GetQueuedOre != null) ? AccessTools.MethodDelegate<Func<Smelter, string>>(GetQueuedOre, (object)null, true) : null);

		private static Smelter regular;

		private static Smelter blast;

		public static bool Ready => QueuedOre != null;

		public static bool IsBlastFurnace(Smelter smelter)
		{
			return smelter.m_name == "$piece_blastfurnace";
		}

		private static Smelter Regular()
		{
			return Prefab(ref regular, "smelter");
		}

		private static Smelter Blast()
		{
			return Prefab(ref blast, "blastfurnace");
		}

		private static Smelter Prefab(ref Smelter cache, string name)
		{
			if ((Object)(object)cache == (Object)null && (Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(name);
				cache = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Smelter>() : null);
			}
			return cache;
		}

		public static ItemConversion RegularConversion(string ore)
		{
			Smelter val = Regular();
			if ((Object)(object)val == (Object)null || !Settings.Ores.ContainsKey(ore))
			{
				return null;
			}
			return val.m_conversion.Find((ItemConversion c) => (Object)(object)c.m_from != (Object)null && ((Object)((Component)c.m_from).gameObject).name == ore);
		}

		public static void Apply(Smelter furnace)
		{
			Smelter val = Blast();
			if ((Object)(object)Regular() == (Object)null || (Object)(object)val == (Object)null)
			{
				return;
			}
			furnace.m_conversion.RemoveAll((ItemConversion c) => (Object)(object)c.m_from != (Object)null && Settings.Ores.ContainsKey(((Object)((Component)c.m_from).gameObject).name));
			if (Settings.Enabled.Value)
			{
				foreach (KeyValuePair<string, ConfigEntry<bool>> ore in Settings.Ores)
				{
					ItemConversion val2 = RegularConversion(ore.Key);
					if (ore.Value.Value && val2 != null)
					{
						furnace.m_conversion.Add(val2);
					}
				}
			}
			bool value = Settings.Enabled.Value;
			furnace.m_maxOre = ((value && Settings.OreCapacity.Value > 0) ? Settings.OreCapacity.Value : val.m_maxOre);
			furnace.m_maxFuel = ((value && Settings.CoalCapacity.Value > 0) ? Settings.CoalCapacity.Value : val.m_maxFuel);
		}

		public static void ApplyToLoaded()
		{
			Smelter[] array = Object.FindObjectsByType<Smelter>((FindObjectsSortMode)0);
			foreach (Smelter val in array)
			{
				if (IsBlastFurnace(val))
				{
					Apply(val);
				}
			}
		}

		public static float SecPerProduct(Smelter smelter)
		{
			if (!IsFast(smelter))
			{
				return smelter.m_secPerProduct;
			}
			return Regular().m_secPerProduct / Settings.Speed.Value;
		}

		public static float CoalPerOre(Smelter smelter)
		{
			if (!IsFast(smelter))
			{
				return smelter.m_fuelPerProduct;
			}
			return (float)Regular().m_fuelPerProduct * Settings.Coal.Value;
		}

		public static bool IsFast(Smelter smelter)
		{
			if (Settings.Enabled.Value && IsBlastFurnace(smelter) && (Object)(object)Regular() != (Object)null)
			{
				return Settings.Ores.ContainsKey(QueuedOre(smelter));
			}
			return false;
		}

		public static void LogRates()
		{
			Smelter val = Regular();
			Smelter val2 = Blast();
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Can't find the regular furnace or the blast furnace (the game changed); the blast furnace stays as the game has it.");
				return;
			}
			string[] array = Settings.Ores.Keys.Where((string ore) => RegularConversion(ore) == null).ToArray();
			if (array.Length != 0)
			{
				Plugin.Log.LogWarning((object)("The regular furnace doesn't take " + string.Join(", ", array) + " (the game changed); the blast furnace won't either."));
			}
			Plugin.Log.LogInfo((object)($"Regular furnace: {val.m_secPerProduct:0.#} s and {val.m_fuelPerProduct} coal per ore. " + $"Blast furnace: {val2.m_secPerProduct:0.#} s and {val2.m_fuelPerProduct} coal per ore, holds " + $"{val2.m_maxOre} ore and {val2.m_maxFuel} coal; the regular furnace's ores take " + $"{val.m_secPerProduct / Settings.Speed.Value:0.##} s and {(float)val.m_fuelPerProduct * Settings.Coal.Value:0.##} coal there."));
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetScene_Awake
	{
		private static void Postfix()
		{
			Furnaces.LogRates();
		}
	}
	[HarmonyPatch(typeof(Smelter), "Awake")]
	internal static class Smelter_Awake
	{
		private static void Postfix(Smelter __instance)
		{
			if (Furnaces.IsBlastFurnace(__instance))
			{
				Furnaces.Apply(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Smelter), "GetItemConversion")]
	internal static class Smelter_GetItemConversion
	{
		private static void Postfix(Smelter __instance, string itemName, ref ItemConversion __result)
		{
			if (__result == null && Furnaces.IsBlastFurnace(__instance))
			{
				__result = Furnaces.RegularConversion(itemName);
			}
		}
	}
	[HarmonyPatch]
	internal static class Smelter_Hover
	{
		private static Smelter swapped;

		private static float savedSecs;

		private static int savedCoal;

		private static IEnumerable<MethodBase> TargetMethods()
		{
			return from method in ((IEnumerable<string>)new string[3] { "OnHoverAddOre", "OnHoverAddFuel", "OnHoverEmptyOre" }).Select((Func<string, MethodBase>)((string name) => AccessTools.Method(typeof(Smelter), name, (Type[])null, (Type[])null)))
				where method != null
				select method;
		}

		[HarmonyPriority(800)]
		private static void Prefix(Smelter __instance)
		{
			if (!((Object)(object)swapped != (Object)null) && Furnaces.IsFast(__instance))
			{
				swapped = __instance;
				savedSecs = __instance.m_secPerProduct;
				savedCoal = __instance.m_fuelPerProduct;
				float secPerProduct = Furnaces.SecPerProduct(__instance);
				int fuelPerProduct = Mathf.RoundToInt(Furnaces.CoalPerOre(__instance));
				__instance.m_secPerProduct = secPerProduct;
				__instance.m_fuelPerProduct = fuelPerProduct;
			}
		}

		private static void Finalizer()
		{
			if (!((Object)(object)swapped == (Object)null))
			{
				if (Object.op_Implicit((Object)(object)swapped))
				{
					swapped.m_secPerProduct = savedSecs;
					swapped.m_fuelPerProduct = savedCoal;
				}
				swapped = null;
			}
		}
	}
	[HarmonyPatch(typeof(Smelter), "UpdateSmelter")]
	internal static class Smelter_UpdateSmelter
	{
		private static readonly FieldInfo SecField = AccessTools.Field(typeof(Smelter), "m_secPerProduct");

		private static readonly FieldInfo FuelField = AccessTools.Field(typeof(Smelter), "m_fuelPerProduct");

		private static readonly MethodInfo SecCall = AccessTools.Method(typeof(Furnaces), "SecPerProduct", (Type[])null, (Type[])null);

		private static readonly MethodInfo CoalCall = AccessTools.Method(typeof(Furnaces), "CoalPerOre", (Type[])null, (Type[])null);

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			List<CodeInstruction> list2 = new List<CodeInstruction>(list);
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < list2.Count; i++)
			{
				if (list2[i].opcode != OpCodes.Ldfld)
				{
					continue;
				}
				FieldInfo fieldInfo = list2[i].operand as FieldInfo;
				MethodInfo methodInfo = ((fieldInfo == SecField) ? SecCall : ((fieldInfo == FuelField) ? CoalCall : null));
				if (!(methodInfo == null))
				{
					CodeInstruction val = list2[i].Clone();
					val.opcode = OpCodes.Call;
					val.operand = methodInfo;
					list2[i] = val;
					if (methodInfo == SecCall)
					{
						num++;
					}
					else
					{
						num2++;
					}
				}
			}
			if (num != 3 || num2 != 1)
			{
				Plugin.Log.LogWarning((object)($"Smelter.UpdateSmelter reads the smelting time {num} times and the coal {num2} times instead of " + "3 and 1 (the game changed); the regular furnace's ores smelt at the blast furnace's own speed."));
				return list;
			}
			return list2;
		}
	}
}