Please disclose if your mod was created primarily 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 StationLimitsFixer v1.4.1
StationLimitsFixer.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; 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: AssemblyTitle("StationLimitsFixer")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("StationLimitsFixer")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("29ed45d8-f11d-4a1c-a98a-2abd302332ef")] [assembly: AssemblyFileVersion("1.2.2.0")] [assembly: AssemblyVersion("1.2.2.0")] namespace StationLimitsFixer; [BepInPlugin("com.custom.stationlimits", "Station Limits Fixer", "1.4.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class StationFixerPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(ZNetScene), "Awake")] public static class ZNetScene_Patch { private static void Postfix() { ApplyChanges(updateActiveSceneObjects: false); } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] public static class BruteForcePlacementPatch { private delegate void SetPlacementGhostValid_Bool_Delegate(Player instance, bool isValid); private delegate void SetPlacementGhostValid_Void_Delegate(Player instance); private delegate void SetInvalidPlacementHighlight_Delegate(Piece instance, bool invalid); private static SetPlacementGhostValid_Bool_Delegate SetGhostValidBool; private static SetPlacementGhostValid_Void_Delegate SetGhostValidVoid; private static SetInvalidPlacementHighlight_Delegate SetHighlight; private static readonly HashSet<string> bulkyPieces = new HashSet<string> { "$piece_smelter", "$piece_charcoalkiln", "$piece_blastfurnace", "$piece_windmill" }; [HarmonyPrepare] private static void Prepare() { MethodInfo methodInfo = AccessTools.Method(typeof(Player), "SetPlacementGhostValid", new Type[1] { typeof(bool) }, (Type[])null); if (methodInfo != null) { SetGhostValidBool = AccessTools.MethodDelegate<SetPlacementGhostValid_Bool_Delegate>(methodInfo, (object)null, true); } else { MethodInfo methodInfo2 = AccessTools.Method(typeof(Player), "SetPlacementGhostValid", new Type[0], (Type[])null); if (methodInfo2 != null) { SetGhostValidVoid = AccessTools.MethodDelegate<SetPlacementGhostValid_Void_Delegate>(methodInfo2, (object)null, true); } } MethodInfo methodInfo3 = AccessTools.Method(typeof(Piece), "SetInvalidPlacementHeightlight", new Type[1] { typeof(bool) }, (Type[])null); if (methodInfo3 != null) { SetHighlight = AccessTools.MethodDelegate<SetInvalidPlacementHighlight_Delegate>(methodInfo3, (object)null, true); } } public static void Postfix(Player __instance, ref GameObject ___m_placementGhost, ref PlacementStatus ___m_placementStatus) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (!BruteForceSmelters.Value || (Object)(object)___m_placementGhost == (Object)null) { return; } Piece component = ___m_placementGhost.GetComponent<Piece>(); RaycastHit val = default(RaycastHit); if (!((Object)(object)component != (Object)null) || !bulkyPieces.Contains(component.m_name) || !PrivateArea.CheckAccess(___m_placementGhost.transform.position, 0f, true, false) || (!AllowSmeltersOnWood.Value && component.m_groundOnly && Physics.Raycast(___m_placementGhost.transform.position + Vector3.up, Vector3.down, ref val, 2f, LayerMask.GetMask(new string[3] { "piece", "Default", "static_solid" })) && (Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Piece>() != (Object)null)) { return; } try { ___m_placementStatus = (PlacementStatus)0; if (SetGhostValidBool != null) { SetGhostValidBool(__instance, isValid: true); } else if (SetGhostValidVoid != null) { SetGhostValidVoid(__instance); } if (SetHighlight != null) { SetHighlight(component, invalid: false); } } catch (Exception ex) { StaticLogger.LogError((object)("[Station Limits Fixer] Failed to override placement for " + component.m_name + ": " + ex.Message)); } } } [HarmonyPatch(typeof(CraftingStation), "Interact")] public static class ForceRecipeScanPatch { private delegate void UpdateKnownRecipes_Delegate(Player instance); private static UpdateKnownRecipes_Delegate UpdateRecipes; [HarmonyPrepare] private static void Prepare() { MethodInfo methodInfo = AccessTools.Method(typeof(Player), "UpdateKnownRecipesList", (Type[])null, (Type[])null); if (methodInfo != null) { UpdateRecipes = AccessTools.MethodDelegate<UpdateKnownRecipes_Delegate>(methodInfo, (object)null, true); } } public static void Prefix(Humanoid user) { if (!AutoScanRecipes.Value || !((Object)(object)user != (Object)null) || !((Object)(object)user == (Object)(object)Player.m_localPlayer) || UpdateRecipes == null) { return; } try { UpdateRecipes(Player.m_localPlayer); } catch (Exception ex) { StaticLogger.LogError((object)("[Station Limits Fixer] Failed to force recipe scan: " + ex.Message)); } } } [CompilerGenerated] private sealed class <DebouncedApplyChanges>d__15 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public StationFixerPlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DebouncedApplyChanges>d__15(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown int num = <>1__state; StationFixerPlugin stationFixerPlugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; case 1: <>1__state = -1; ApplyChanges(updateActiveSceneObjects: true); stationFixerPlugin._applyChangesCoroutine = null; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static ConfigEntry<float> HitboxSize; public static ConfigEntry<float> MaxConnectionDistance; public static ConfigEntry<bool> RemoveRoofRequirement; public static ConfigEntry<bool> BruteForceSmelters; public static ConfigEntry<string> ExcludedHitboxPieces; public static ConfigEntry<bool> AllowSmeltersOnWood; public static ConfigEntry<bool> AutoScanRecipes; internal static ManualLogSource StaticLogger; private Coroutine _applyChangesCoroutine; private static Dictionary<Collider, Vector3> originalBoxSizes = new Dictionary<Collider, Vector3>(); private static Dictionary<Collider, Vector2> originalCapsuleSizes = new Dictionary<Collider, Vector2>(); private static Dictionary<Collider, float> originalSphereRadii = new Dictionary<Collider, float>(); private static bool _azuWorkbenchPresent; private void Awake() { //IL_016f: Unknown result type (might be due to invalid IL or missing references) StaticLogger = ((BaseUnityPlugin)this).Logger; _azuWorkbenchPresent = Chainloader.PluginInfos.ContainsKey("Azumatt.AzuWorkbenchTweaks"); if (_azuWorkbenchPresent) { StaticLogger.LogWarning((object)"AzuWorkbenchTweaks detected. Skipping MaxConnectionDistance and RemoveRoofRequirement to avoid conflicts."); } HitboxSize = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ImprovementHitboxSize", 0.6f, "Size of the physical footprint. 0.1 is tiny."); AutoScanRecipes = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoScanRecipes", true, "If true, automatically scans for newly unlocked recipes every time you open a crafting station."); BruteForceSmelters = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "ForceSmelterPlacement", true, "If true, Smelters, Kilns, etc. can be placed on uneven terrain."); AllowSmeltersOnWood = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "AllowSmeltersOnWood", false, "If true, allows placing heavy Smelters on wooden floors."); ExcludedHitboxPieces = ((BaseUnityPlugin)this).Config.Bind<string>("Advanced", "ExcludedHitboxPieces", "blackforge_ext1,piece_workbench_ext2", "Comma-separated list of prefab names to skip when shrinking hitboxes. Applies on load."); HitboxSize.SettingChanged += delegate { RequestApplyChanges(); }; if (!_azuWorkbenchPresent) { MaxConnectionDistance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MaxRange", 25f, "Maximum distance between a crafting station and its improvements."); RemoveRoofRequirement = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "NoRoofRequired", false, "If true, main crafting stations work even without a roof or in the rain."); MaxConnectionDistance.SettingChanged += delegate { RequestApplyChanges(); }; RemoveRoofRequirement.SettingChanged += delegate { RequestApplyChanges(); }; } new Harmony("com.custom.stationlimits").PatchAll(); StaticLogger.LogInfo((object)"Station Limits Fixer initialized."); } private void RequestApplyChanges() { if (_applyChangesCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_applyChangesCoroutine); } _applyChangesCoroutine = ((MonoBehaviour)this).StartCoroutine(DebouncedApplyChanges()); } [IteratorStateMachine(typeof(<DebouncedApplyChanges>d__15))] private IEnumerator DebouncedApplyChanges() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DebouncedApplyChanges>d__15(0) { <>4__this = this }; } public static void ApplyChanges(bool updateActiveSceneObjects) { //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNetScene.instance == (Object)null) { return; } int num = 0; HashSet<string> hashSet = new HashSet<string>(ExcludedHitboxPieces.Value.Replace(" ", "").Split(new char[1] { ',' })); CraftingStation val = default(CraftingStation); StationExtension val2 = default(StationExtension); Piece val3 = default(Piece); foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { prefab.TryGetComponent<CraftingStation>(ref val); prefab.TryGetComponent<StationExtension>(ref val2); if ((Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null) { continue; } if (prefab.TryGetComponent<Piece>(ref val3)) { val3.m_spaceRequirement = 0f; } if ((Object)(object)val2 != (Object)null && !hashSet.Contains(((Object)prefab).name)) { Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(); foreach (Collider val4 in componentsInChildren) { if (val4.isTrigger) { continue; } float value = HitboxSize.Value; BoxCollider val5 = (BoxCollider)(object)((val4 is BoxCollider) ? val4 : null); if (val5 != null) { if (!originalBoxSizes.ContainsKey((Collider)(object)val5)) { originalBoxSizes[(Collider)(object)val5] = val5.size; } val5.size = originalBoxSizes[(Collider)(object)val5] * value; continue; } CapsuleCollider val6 = (CapsuleCollider)(object)((val4 is CapsuleCollider) ? val4 : null); if (val6 != null) { if (!originalCapsuleSizes.ContainsKey((Collider)(object)val6)) { originalCapsuleSizes[(Collider)(object)val6] = new Vector2(val6.radius, val6.height); } val6.radius = originalCapsuleSizes[(Collider)(object)val6].x * value; val6.height = originalCapsuleSizes[(Collider)(object)val6].y * value; continue; } SphereCollider val7 = (SphereCollider)(object)((val4 is SphereCollider) ? val4 : null); if (val7 != null) { if (!originalSphereRadii.ContainsKey((Collider)(object)val7)) { originalSphereRadii[(Collider)(object)val7] = val7.radius; } val7.radius = originalSphereRadii[(Collider)(object)val7] * value; } } } if ((Object)(object)val2 != (Object)null) { if (!_azuWorkbenchPresent) { val2.m_maxStationDistance = MaxConnectionDistance.Value; } val2.m_continousConnection = true; } if ((Object)(object)val != (Object)null && !_azuWorkbenchPresent) { val.m_craftRequireRoof = !RemoveRoofRequirement.Value; } num++; } if (updateActiveSceneObjects) { StationExtension[] array = Object.FindObjectsByType<StationExtension>((FindObjectsSortMode)0); foreach (StationExtension val8 in array) { if (!_azuWorkbenchPresent) { val8.m_maxStationDistance = MaxConnectionDistance.Value; } val8.m_continousConnection = true; } if (!_azuWorkbenchPresent) { CraftingStation[] array2 = Object.FindObjectsByType<CraftingStation>((FindObjectsSortMode)0); for (int i = 0; i < array2.Length; i++) { array2[i].m_craftRequireRoof = !RemoveRoofRequirement.Value; } } } StaticLogger.LogInfo((object)$"Successfully patched {num} prefabs."); } }