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 FuelCapacity v0.1.0
BepInEx/plugins/FuelCapacity/FuelCapacity.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using FuelCapacity.Core; using HarmonyLib; 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("FuelCapacity")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("FuelCapacity")] [assembly: AssemblyTitle("FuelCapacity")] [assembly: AssemblyVersion("0.1.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 FuelCapacity { internal sealed class CapacityNetwork { private const string Query = "FuelCapacity_Query_v1"; private const string Request = "FuelCapacity_Command_v1"; private const string State = "FuelCapacity_State_v1"; private const string Reply = "FuelCapacity_Reply_v1"; private readonly Plugin plugin; private readonly HashSet<ZRpc> registered = new HashSet<ZRpc>(); private readonly Dictionary<ZRpc, float> lastRequest = new Dictionary<ZRpc, float>(); private ZNet session; private FuelSettings effective; private Terminal output; private float nextTick; private float nextQuery; private float nextPrune; private long revision; private long receivedRevision = -1L; internal CapacityNetwork(Plugin plugin) { this.plugin = plugin; } internal void Stop() { session = null; effective = null; registered.Clear(); lastRequest.Clear(); output = null; nextTick = (nextQuery = (nextPrune = 0f)); revision = 0L; receivedRevision = -1L; plugin.Machines.Restore(); } private void EnsureSession() { ZNet instance = ZNet.instance; if (session != instance) { Stop(); session = instance; if (Object.op_Implicit((Object)(object)session) && session.IsServer()) { Apply(plugin.Configured); } } } internal void Update() { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown EnsureSession(); if (!Object.op_Implicit((Object)(object)session) || Time.unscaledTime < nextTick) { return; } nextTick = Time.unscaledTime + 0.25f; if (Time.unscaledTime >= nextPrune) { nextPrune = Time.unscaledTime + 15f; plugin.Machines.Prune(); } List<ZNetPeer> peers = session.GetPeers(); foreach (ZNetPeer item in peers) { if (item.IsReady() && item.m_rpc != null && registered.Add(item.m_rpc)) { item.m_rpc.Register("FuelCapacity_Query_v1", new Method(OnQuery)); item.m_rpc.Register<string>("FuelCapacity_Command_v1", (Action<ZRpc, string>)OnRequest); item.m_rpc.Register<ZPackage>("FuelCapacity_State_v1", (Action<ZRpc, ZPackage>)OnState); item.m_rpc.Register<string>("FuelCapacity_Reply_v1", (Action<ZRpc, string>)OnReply); } } ZRpc[] array = registered.Where((ZRpc r) => !peers.Any((ZNetPeer p) => p.m_rpc == r)).ToArray(); foreach (ZRpc val in array) { registered.Remove(val); lastRequest.Remove(val); } if (!session.IsServer() && Time.unscaledTime >= nextQuery) { nextQuery = Time.unscaledTime + (float)((effective == null) ? 1 : 10); ZNetPeer serverPeer = session.GetServerPeer(); if (serverPeer != null) { serverPeer.m_rpc.Invoke("FuelCapacity_Query_v1", Array.Empty<object>()); } } } private void Apply(FuelSettings next) { effective = next; plugin.Machines.Set(next); } private ZNetPeer Peer(ZRpc rpc) { return ((IEnumerable<ZNetPeer>)session.GetPeers()).FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer p) => p.IsReady() && p.m_rpc == rpc)); } private bool Throttled(ZRpc rpc) { if (lastRequest.TryGetValue(rpc, out var value) && Time.unscaledTime - value < 0.25f) { return true; } lastRequest[rpc] = Time.unscaledTime; return false; } internal static bool IsAdmin(ZNetPeer peer) { if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer() && peer != null && peer.IsReady() && peer.m_socket != null) { return ZNet.instance.IsAdmin(peer.m_socket.GetHostName()); } return false; } private bool FromServer(ZRpc rpc) { if (Object.op_Implicit((Object)(object)session) && !session.IsServer()) { return session.GetServerPeer()?.m_rpc == rpc; } return false; } private void OnQuery(ZRpc rpc) { if (Object.op_Implicit((Object)(object)session) && session.IsServer() && Peer(rpc) != null && !Throttled(rpc)) { Send(rpc); } } private void OnRequest(ZRpc rpc, string command) { if (!Object.op_Implicit((Object)(object)session) || !session.IsServer()) { return; } ZNetPeer val = Peer(rpc); if (val != null) { if (Throttled(rpc)) { rpc.Invoke("FuelCapacity_Reply_v1", new object[1] { "Please wait a moment and retry fuelcapacity." }); } else if (!IsAdmin(val)) { rpc.Invoke("FuelCapacity_Reply_v1", new object[1] { "Only the host or a server admin may change fuel capacity." }); } else if (command == null || command.Length > 256) { rpc.Invoke("FuelCapacity_Reply_v1", new object[1] { "Command is too long." }); } else { rpc.Invoke("FuelCapacity_Reply_v1", new object[1] { Execute(command.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries), val.m_socket.GetHostName()) }); } } } private void OnReply(ZRpc rpc, string message) { if (FromServer(rpc) && message != null && message.Length <= 4096 && Object.op_Implicit((Object)(object)output)) { output.AddString(message); } } private void Send(ZRpc rpc) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(1); val.Write(revision); val.Write(effective.Capacity); val.Write(effective.Overrides); rpc.Invoke("FuelCapacity_State_v1", new object[1] { val }); } private void Publish() { foreach (ZNetPeer peer in session.GetPeers()) { if (peer.IsReady()) { Send(peer.m_rpc); } } } private void OnState(ZRpc rpc, ZPackage packet) { if (!FromServer(rpc)) { return; } try { long incoming; FuelSettings fuelSettings = Decode(packet, receivedRevision, out incoming); if (fuelSettings != null) { Apply(fuelSettings); receivedRevision = incoming; } } catch (Exception ex) { plugin.Warn("Rejected fuel settings: " + ex.Message); } } internal static FuelSettings Decode(ZPackage packet, long previous, out long incoming) { if (packet == null || packet.Size() > 16384) { throw new ArgumentException("Invalid settings packet size."); } if (packet.ReadInt() != 1) { throw new ArgumentException("Unsupported settings version."); } incoming = packet.ReadLong(); if (incoming < 0) { throw new ArgumentException("Invalid settings revision."); } FuelSettings result = new FuelSettings(packet.ReadInt(), packet.ReadString()); if (packet.GetPos() != packet.Size()) { throw new ArgumentException("Trailing settings data."); } if (incoming >= previous) { return result; } return null; } internal void Command(string[] input, Terminal terminal) { EnsureSession(); output = terminal; string[] array = input.Skip(1).ToArray(); if (array.Length == 0 || (array.Length == 1 && array[0].Equals("status", StringComparison.OrdinalIgnoreCase))) { terminal.AddString(effective?.ToString() ?? "Join a world; waiting for server fuel settings."); return; } if (array.Length == 1 && array[0].Equals("list", StringComparison.OrdinalIgnoreCase)) { string text = plugin.Machines.List(); terminal.AddString((text.Length == 0) ? "No fuel-fed production units loaded nearby." : text); return; } if (!Object.op_Implicit((Object)(object)session)) { terminal.AddString("Join a world first."); return; } if (session.IsServer()) { terminal.AddString(Execute(array, "local host/console")); return; } if (effective == null) { terminal.AddString("Waiting for the server's fuel settings. The server must have this mod."); return; } string text2 = string.Join(" ", array); if (text2.Length > 256) { terminal.AddString("Command is too long."); return; } ZNetPeer serverPeer = session.GetServerPeer(); if (serverPeer != null) { serverPeer.m_rpc.Invoke("FuelCapacity_Command_v1", new object[1] { text2 }); } } private string Execute(string[] args, string actor) { try { FuelSettings fuelSettings; if (args.Length == 1 && args[0].Equals("reload", StringComparison.OrdinalIgnoreCase)) { fuelSettings = plugin.Reload(); } else { if (args.Length == 1 && FuelSettings.TryCapacity(args[0], out var result)) { fuelSettings = new FuelSettings(result, effective.Overrides); } else if (args.Length == 3 && args[0].Equals("set", StringComparison.OrdinalIgnoreCase) && FuelSettings.TryCapacity(args[2], out result)) { fuelSettings = effective.WithOverride(args[1], result); } else { if (args.Length != 2 || !args[0].Equals("reset", StringComparison.OrdinalIgnoreCase)) { return "Usage: fuelcapacity <0–100000> | set <prefab> <0–100000> | reset <prefab> | reload | status | list"; } fuelSettings = effective.WithOverride(args[1], null); } plugin.Save(fuelSettings); } Apply(fuelSettings); revision++; Publish(); plugin.Audit("Fuel settings changed by " + actor + ": " + fuelSettings); return fuelSettings?.ToString() + " Applied to loaded units; settings persist in the server config."; } catch (Exception ex) { plugin.Warn("Fuel config change failed: " + ex.Message); return "Fuel config change failed: " + ex.Message; } } } internal sealed class Machines { private sealed class Entry { internal Smelter Machine; internal int Original; internal string Prefab; internal int Capacity { get { return Machine.m_maxFuel; } set { Machine.m_maxFuel = value; } } } private readonly Dictionary<Smelter, Entry> entries = new Dictionary<Smelter, Entry>(); private FuelSettings effective; internal void Track(Smelter machine) { if (entries.ContainsKey(machine)) { return; } int maxFuel = machine.m_maxFuel; if (maxFuel <= 0 || !Object.op_Implicit((Object)(object)machine.m_fuelItem) || !FuelSettings.UsesCoal(((Object)((Component)machine.m_fuelItem).gameObject).name, machine.m_fuelItem.m_itemData?.m_shared?.m_name)) { return; } string text = ((Object)((Component)machine).gameObject).name; ZNetView val = ((Component)machine).GetComponent<ZNetView>() ?? ((Component)machine).GetComponentInParent<ZNetView>(); if (Object.op_Implicit((Object)(object)val) && val.IsValid() && Object.op_Implicit((Object)(object)ZNetScene.instance)) { GameObject prefab = ZNetScene.instance.GetPrefab(val.GetZDO().GetPrefab()); if (Object.op_Implicit((Object)(object)prefab)) { text = ((Object)prefab).name; } } if (text.EndsWith("(Clone)")) { text = text.Substring(0, text.Length - 7); } Entry entry = new Entry { Machine = machine, Original = maxFuel, Prefab = text }; entries.Add(machine, entry); Apply(entry); } private void Apply(Entry entry) { entry.Capacity = effective?.Resolve(entry.Prefab, entry.Original, usesFuel: true) ?? entry.Original; } internal void Prune() { Smelter[] array = entries.Keys.Where((Smelter k) => !Object.op_Implicit((Object)(object)k)).ToArray(); foreach (Smelter key in array) { entries.Remove(key); } } internal void Set(FuelSettings settings) { effective = settings; Entry[] array = entries.Values.ToArray(); foreach (Entry entry in array) { if (!Object.op_Implicit((Object)(object)entry.Machine)) { entries.Remove(entry.Machine); } else { Apply(entry); } } } internal void Restore() { Set(null); } internal string List() { return string.Join("\n", from e in entries.Values where Object.op_Implicit((Object)(object)e.Machine) group e by e.Prefab into g orderby g.Key select g.Key + ": " + g.First().Capacity + " fuel (original " + g.First().Original + ", " + g.Count() + " loaded)"); } } [HarmonyPatch] internal static class Patches { [HarmonyPatch(typeof(Smelter), "Awake")] [HarmonyPostfix] [HarmonyPriority(0)] private static void SmelterAwake(Smelter __instance) { Plugin.Instance?.Machines.Track(__instance); } } [BepInPlugin("cheyenne.fuelcapacity", "Fuel Capacity", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "cheyenne.fuelcapacity"; public const string Version = "0.1.0"; internal static Plugin Instance; internal FuelSettings Configured; internal CapacityNetwork Network; internal readonly Machines Machines = new Machines(); private ConfigEntry<int> capacity; private ConfigEntry<string> overrides; private Harmony harmony; private bool stopped; private void Awake() { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) Instance = this; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; capacity = ((BaseUnityPlugin)this).Config.Bind<int>("Fuel", "Capacity", 40, "Coal capacity for coal-fueled smelters and blast furnaces. 0 = original; range 0–100000. Server controls multiplayer settings."); overrides = ((BaseUnityPlugin)this).Config.Bind<string>("Fuel", "PrefabOverrides", "", "Optional prefab capacities, e.g. smelter=40;blastfurnace=80. 0 keeps that prefab's original capacity."); if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath)) { ((BaseUnityPlugin)this).Config.Save(); } try { Configured = ReadSettings(); } catch (Exception ex) { Configured = new FuelSettings(40, ""); Warn("Invalid config; using 40 until corrected and reloaded: " + ex.Message); } Network = new CapacityNetwork(this); try { harmony = new Harmony("cheyenne.fuelcapacity"); harmony.PatchAll(); new ConsoleCommand("fuelcapacity", "fuelcapacity [status|list|<number>|set <prefab> <number>|reset <prefab>|reload]. Changes require server admin.", (ConsoleEvent)delegate(ConsoleEventArgs a) { Network.Command(a.Args, a.Context); }, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Fuel Capacity 0.1.0 loaded. Default: " + Configured.Capacity + ". Command: fuelcapacity.")); } catch (Exception ex2) { stopped = true; Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } ((BaseUnityPlugin)this).Logger.LogError((object)("Fuel Capacity disabled: " + ex2)); } } private FuelSettings ReadSettings() { return new FuelSettings(capacity.Value, overrides.Value); } internal FuelSettings Reload() { int value = capacity.Value; string value2 = overrides.Value; try { ((BaseUnityPlugin)this).Config.Reload(); return Configured = ReadSettings(); } catch { capacity.Value = value; overrides.Value = value2; throw; } } internal void Save(FuelSettings next) { int value = capacity.Value; string value2 = overrides.Value; try { capacity.Value = next.Capacity; overrides.Value = next.Overrides; ((BaseUnityPlugin)this).Config.Save(); Configured = next; } catch { capacity.Value = value; overrides.Value = value2; throw; } } private void Update() { if (stopped) { return; } try { Network.Update(); } catch (Exception ex) { Warn("Fuel networking failed: " + ex.Message); } } private void OnDestroy() { Network?.Stop(); Machines.Restore(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } Instance = null; } internal void Warn(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); } internal void Audit(string message) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); } } } namespace FuelCapacity.Core { public sealed class FuelSettings { public const int DefaultCapacity = 40; public const int Maximum = 100000; public const int MaximumOverrides = 64; private readonly Dictionary<string, int> overrides; public int Capacity { get; } public string Overrides => string.Join(";", from p in overrides.OrderBy<KeyValuePair<string, int>, string>((KeyValuePair<string, int> p) => p.Key, StringComparer.OrdinalIgnoreCase) select p.Key + "=" + p.Value.ToString(CultureInfo.InvariantCulture)); public FuelSettings(int capacity, string text) { if (capacity < 0 || capacity > 100000) { throw new ArgumentException("Capacity must be 0–100000; 0 keeps the original capacity."); } Capacity = capacity; overrides = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); if (text == null || text.Length > 8192) { throw new ArgumentException("Invalid prefab overrides."); } if (text.Trim().Length == 0) { return; } string[] array = text.Split(';'); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split('='); if (array2.Length != 2 || !ValidName(array2[0].Trim()) || !TryCapacity(array2[1].Trim(), out var result)) { throw new ArgumentException("Use prefab=value entries separated by semicolons, e.g. smelter=40;blastfurnace=80."); } if (overrides.ContainsKey(array2[0].Trim())) { throw new ArgumentException("Duplicate prefab override: " + array2[0].Trim()); } overrides.Add(array2[0].Trim(), result); if (overrides.Count > 64) { throw new ArgumentException("At most 64 prefab overrides are supported."); } } } public static bool ValidName(string name) { if (name != null) { return Regex.IsMatch(name, "\\A[A-Za-z0-9_-]{1,80}\\z"); } return false; } public static bool UsesCoal(string fuelPrefab, string sharedName) { if (!string.Equals(fuelPrefab, "Coal", StringComparison.OrdinalIgnoreCase)) { return sharedName == "$item_coal"; } return true; } public static bool TryCapacity(string value, out int result) { if (int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result) && result >= 0) { return result <= 100000; } return false; } public int Resolve(string prefab, int original, bool usesFuel) { if (!usesFuel || original <= 0) { return original; } int value; int num = ((prefab != null && overrides.TryGetValue(prefab, out value)) ? value : Capacity); if (num != 0) { return num; } return original; } public FuelSettings WithOverride(string prefab, int? value) { if (!ValidName(prefab)) { throw new ArgumentException("Use the prefab name (letters, digits, underscores or hyphens)."); } Dictionary<string, int> dictionary = new Dictionary<string, int>(overrides, StringComparer.OrdinalIgnoreCase); if (value.HasValue) { dictionary[prefab] = value.Value; } else { dictionary.Remove(prefab); } return new FuelSettings(Capacity, string.Join(";", dictionary.Select((KeyValuePair<string, int> p) => p.Key + "=" + p.Value.ToString(CultureInfo.InvariantCulture)))); } public override string ToString() { return "Default fuel capacity: " + Capacity + " (0 = original). Overrides: " + ((overrides.Count == 0) ? "none" : Overrides); } } }