Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of FrizzQOL Smelter Control v0.1.0
FrizzQOL.SmelterControl.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Threading; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("FrizzQOL.SmelterControl")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("FrizzQOL.SmelterControl")] [assembly: AssemblyTitle("FrizzQOL.SmelterControl")] [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 SmelterControl { [HarmonyPatch(typeof(Smelter), "Awake")] internal static class SmelterAwakePatch { private static void Postfix(Smelter __instance) { try { SmelterApplier.Apply(__instance); } catch (Exception ex) { Plugin.LogOnce(ex.Message); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneAwakePatch { private static void Postfix(ZNetScene __instance) { try { SmelterApplier.ApplyPrefabs(__instance); } catch (Exception ex) { Plugin.LogOnce(ex.Message); } } } [HarmonyPatch(typeof(Smelter), "RPC_AddOre")] internal static class AddOreCapPatch { private static readonly MethodInfo QueueSize = AccessTools.Method(typeof(Smelter), "GetQueueSize", (Type[])null, (Type[])null); private static readonly FieldInfo NetView = AccessTools.Field(typeof(Smelter), "m_nview"); private static bool Prefix(Smelter __instance) { try { if (QueueSize == null) { Plugin.LogOnce("Smelter.GetQueueSize was missing."); } if (NetView == null) { Plugin.LogOnce("Smelter.m_nview was missing."); } if ((Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).gameObject == (Object)null || !SmelterRules.IsControlled(SmelterRules.PrefabName(((Object)((Component)__instance).gameObject).name))) { return true; } if (!IsOwner(__instance)) { return true; } int queueSize = 0; if (QueueSize != null && QueueSize.Invoke(__instance, null) is int num) { queueSize = num; } return !SmelterRules.OreIsFull(queueSize, __instance.m_maxOre); } catch (Exception ex) { Plugin.LogOnce(ex.Message); return true; } } internal static bool IsOwner(Smelter smelter) { if ((Object)(object)smelter == (Object)null) { return false; } if (NetView == null) { Plugin.LogOnce("Smelter.m_nview was missing."); return false; } object? value = NetView.GetValue(smelter); ZNetView val = (ZNetView)((value is ZNetView) ? value : null); if ((Object)(object)val != (Object)null && val.IsValid()) { return val.IsOwner(); } return false; } } [HarmonyPatch(typeof(Smelter), "RPC_AddFuel")] internal static class AddFuelCapPatch { private static readonly MethodInfo FuelAmount = AccessTools.Method(typeof(Smelter), "GetFuel", (Type[])null, (Type[])null); private static bool Prefix(Smelter __instance) { try { if (FuelAmount == null) { Plugin.LogOnce("Smelter.GetFuel was missing."); } if ((Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).gameObject == (Object)null || !SmelterRules.IsControlled(SmelterRules.PrefabName(((Object)((Component)__instance).gameObject).name))) { return true; } if (!AddOreCapPatch.IsOwner(__instance) || (Object)(object)__instance.m_fuelItem == (Object)null) { return true; } float fuel = 0f; if (FuelAmount != null && FuelAmount.Invoke(__instance, null) is float num) { fuel = num; } return !SmelterRules.FuelIsFull(fuel, __instance.m_maxFuel); } catch (Exception ex) { Plugin.LogOnce(ex.Message); return true; } } } [BepInPlugin("com.frizzqol.smeltercontrol", "FrizzQOL Smelter Control", "0.1.0")] public class Plugin : BaseUnityPlugin { internal struct StationSettings { public float Seconds; public int Input; public int Fuel; } public const string PluginGuid = "com.frizzqol.smeltercontrol"; public const string PluginName = "FrizzQOL Smelter Control"; public const string PluginVersion = "0.1.0"; internal static ConfigEntry<float> SmelterSeconds; internal static ConfigEntry<int> SmelterOre; internal static ConfigEntry<int> SmelterFuel; internal static ConfigEntry<float> BlastSeconds; internal static ConfigEntry<int> BlastOre; internal static ConfigEntry<int> BlastFuel; internal static ConfigEntry<float> KilnSeconds; internal static ConfigEntry<int> KilnWood; private static readonly HashSet<string> Logged = new HashSet<string>(); private const long ConfigReloadQuietTicks = 2500000L; private Harmony _harmony; private FileSystemWatcher _configWatcher; private long _configQuietUntilTicks; private int _applyQueued; internal static Plugin Instance { get; private set; } private void Awake() { //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Expected O, but got Unknown Instance = this; SmelterSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Smelter", "Seconds", 0f, "Seconds per bar. 0 keeps the normal 30. Below 0 does the same."); SmelterOre = ((BaseUnityPlugin)this).Config.Bind<int>("Smelter", "Ore", 0, "Ore the smelter will hold. 0 keeps the normal 10. Below 0 does the same."); SmelterFuel = ((BaseUnityPlugin)this).Config.Bind<int>("Smelter", "Fuel", 0, "Coal the smelter will hold. 0 keeps the normal 20. Below 0 does the same."); BlastSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("BlastFurnace", "Seconds", 0f, "Seconds per bar. 0 keeps the normal 30. Below 0 does the same."); BlastOre = ((BaseUnityPlugin)this).Config.Bind<int>("BlastFurnace", "Ore", 0, "Ore the blast furnace will hold. 0 keeps the normal 10. Below 0 does the same."); BlastFuel = ((BaseUnityPlugin)this).Config.Bind<int>("BlastFurnace", "Fuel", 0, "Coal the blast furnace will hold. 0 keeps the normal 20. Below 0 does the same."); KilnSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("CharcoalKiln", "Seconds", 0f, "Seconds per coal. 0 keeps the normal 15. Below 0 does the same."); KilnWood = ((BaseUnityPlugin)this).Config.Bind<int>("CharcoalKiln", "Wood", 0, "Wood the kiln will hold. 0 keeps the normal 25. Below 0 does the same."); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { QueueApply(); }; WatchConfigFile(); _harmony = new Harmony("com.frizzqol.smeltercontrol"); try { _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"FrizzQOL Smelter Control 0.1.0 loaded"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Harmony patch failed: " + ex.ToString())); _harmony.UnpatchSelf(); } } private void QueueApply() { if (Interlocked.CompareExchange(ref _applyQueued, 1, 0) == 0) { if ((Object)(object)ThreadingHelper.Instance != (Object)null) { ThreadingHelper.Instance.StartSyncInvoke((Action)ApplyQueued); } else { ApplyQueued(); } } } private void ApplyQueued() { Interlocked.Exchange(ref _applyQueued, 0); SmelterApplier.ApplyAll(); } private void WatchConfigFile() { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; string directoryName = Path.GetDirectoryName(configFilePath); string fileName = Path.GetFileName(configFilePath); if (!string.IsNullOrEmpty(directoryName) && !string.IsNullOrEmpty(fileName)) { _configWatcher = new FileSystemWatcher(directoryName, fileName); _configWatcher.NotifyFilter = NotifyFilters.LastWrite; _configWatcher.Changed += OnConfigFileChanged; _configWatcher.EnableRaisingEvents = true; } } private void OnConfigFileChanged(object sender, FileSystemEventArgs args) { long ticks = DateTime.UtcNow.Ticks; long num = Interlocked.Read(in _configQuietUntilTicks); if (ticks >= num && Interlocked.CompareExchange(ref _configQuietUntilTicks, ticks + 2500000, num) == num) { if ((Object)(object)ThreadingHelper.Instance != (Object)null) { ThreadingHelper.Instance.StartSyncInvoke((Action)ReloadConfigFile); } else { ReloadConfigFile(); } } } private void ReloadConfigFile() { ((BaseUnityPlugin)this).Config.Reload(); } internal static StationSettings ConfigFor(string prefabName) { return prefabName switch { "piece_blastfurnace" => new StationSettings { Seconds = ReadSeconds(BlastSeconds, "BlastFurnace Seconds"), Input = ReadCount(BlastOre, "BlastFurnace Ore"), Fuel = ReadCount(BlastFuel, "BlastFurnace Fuel") }, "piece_charcoalkiln" => new StationSettings { Seconds = ReadSeconds(KilnSeconds, "CharcoalKiln Seconds"), Input = ReadCount(KilnWood, "CharcoalKiln Wood"), Fuel = 0 }, "piece_smelter" => new StationSettings { Seconds = ReadSeconds(SmelterSeconds, "Smelter Seconds"), Input = ReadCount(SmelterOre, "Smelter Ore"), Fuel = ReadCount(SmelterFuel, "Smelter Fuel") }, _ => new StationSettings { Seconds = 0f, Input = 0, Fuel = 0 }, }; } internal static void LogOnce(string message) { if (!string.IsNullOrEmpty(message) && !Logged.Contains(message)) { Logged.Add(message); LogWarning(message); } } internal static void LogError(string message) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogError((object)message); } } private static float ReadSeconds(ConfigEntry<float> entry, string label) { float num = entry?.Value ?? 0f; if (num < 0f) { LogOnce(label + " below 0 keeps the normal value."); } return num; } private static int ReadCount(ConfigEntry<int> entry, string label) { int num = entry?.Value ?? 0; if (num < 0) { LogOnce(label + " below 0 keeps the normal value."); } return num; } private static void LogWarning(string message) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)message); } } } internal static class SmelterApplier { private struct VanillaStats { public float Seconds; public int Ore; public int Fuel; } private static readonly Dictionary<string, VanillaStats> Vanilla = new Dictionary<string, VanillaStats>(); internal static void Apply(Smelter smelter) { if (!((Object)(object)smelter == (Object)null)) { string objectName = (((Object)(object)((Component)smelter).gameObject != (Object)null) ? ((Object)((Component)smelter).gameObject).name : null); ApplyNamed(smelter, SmelterRules.PrefabName(objectName)); } } internal static void ApplyPrefabs(ZNetScene scene) { if ((Object)(object)scene == (Object)null) { return; } if (!(AccessTools.Field(typeof(ZNetScene), "m_prefabs")?.GetValue(scene) is List<GameObject> list)) { Plugin.LogOnce("ZNetScene prefab list was missing. Smelter config was not applied."); return; } bool flag = false; bool flag2 = false; bool flag3 = false; for (int i = 0; i < list.Count; i++) { GameObject val = list[i]; if ((Object)(object)val == (Object)null) { continue; } string text = SmelterRules.PrefabName(((Object)val).name); if (SmelterRules.IsControlled(text)) { Smelter component = val.GetComponent<Smelter>(); switch (text) { case "piece_smelter": flag |= (Object)(object)component != (Object)null; break; case "piece_blastfurnace": flag2 |= (Object)(object)component != (Object)null; break; case "piece_charcoalkiln": flag3 |= (Object)(object)component != (Object)null; break; } ApplyNamed(component, text); } } if (!flag) { Plugin.LogOnce("Missing smelter prefab: piece_smelter"); } if (!flag2) { Plugin.LogOnce("Missing smelter prefab: piece_blastfurnace"); } if (!flag3) { Plugin.LogOnce("Missing smelter prefab: piece_charcoalkiln"); } } internal static void ApplyAll() { if ((Object)(object)ZNetScene.instance != (Object)null) { ApplyPrefabs(ZNetScene.instance); } Smelter[] array = Object.FindObjectsByType<Smelter>((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { Apply(array[i]); } } private static void ApplyNamed(Smelter smelter, string prefabName) { if (!((Object)(object)smelter == (Object)null) && SmelterRules.IsControlled(prefabName)) { if (!Vanilla.ContainsKey(prefabName)) { Vanilla[prefabName] = new VanillaStats { Seconds = smelter.m_secPerProduct, Ore = smelter.m_maxOre, Fuel = smelter.m_maxFuel }; } VanillaStats vanillaStats = Vanilla[prefabName]; Plugin.StationSettings stationSettings = Plugin.ConfigFor(prefabName); smelter.m_secPerProduct = SmelterRules.ResolveSeconds(stationSettings.Seconds, vanillaStats.Seconds); smelter.m_maxOre = SmelterRules.ResolveCount(stationSettings.Input, vanillaStats.Ore); if (SmelterRules.WritesFuel(prefabName, (Object)(object)smelter.m_fuelItem != (Object)null)) { smelter.m_maxFuel = SmelterRules.ResolveCount(stationSettings.Fuel, vanillaStats.Fuel); } } } } public static class SmelterRules { public const string SmelterPrefab = "piece_smelter"; public const string BlastFurnacePrefab = "piece_blastfurnace"; public const string CharcoalKilnPrefab = "piece_charcoalkiln"; public static float ResolveSeconds(float configured, float vanilla) { if (configured <= 0f) { return vanilla; } return configured; } public static int ResolveCount(int configured, int vanilla) { if (configured <= 0) { return vanilla; } return configured; } public static bool IsControlled(string prefabName) { if (!(prefabName == "piece_smelter") && !(prefabName == "piece_blastfurnace")) { return prefabName == "piece_charcoalkiln"; } return true; } public static bool WritesFuel(string prefabName, bool hasFuelItem) { if (!hasFuelItem) { return false; } if (!(prefabName == "piece_smelter")) { return prefabName == "piece_blastfurnace"; } return true; } public static bool OreIsFull(int queueSize, int maxOre) { return queueSize >= maxOre; } public static bool FuelIsFull(float fuel, int maxFuel) { return fuel > (float)(maxFuel - 1); } public static string PrefabName(string objectName) { if (string.IsNullOrEmpty(objectName)) { return ""; } int num = objectName.IndexOf("(Clone)"); if (num < 0) { return objectName; } return objectName.Substring(0, num).Trim(); } } }