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 ZenConstruction v1.3.1
plugins/ZenConstruction.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using JetBrains.Annotations; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using Zen; using Zen.Lib; using Zen.Lib.Config; using Zen.Lib.Controls; using ZenConstruction.Section; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ZenConstruction")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("ZenDragon")] [assembly: AssemblyProduct("ZenConstruction")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("1.3.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.3.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 ZenConstruction { internal static class Configs { public static readonly ConfigEntry<bool> PavedRoadNoDeform; public static readonly ConfigEntry<bool> ResetBuildCursorRotation; public static readonly ConfigEntry<bool> AllowTorchWithHammer; public static readonly ConfigEntry<bool> ShowSnapIcon; public static readonly ConfigEntry<StringList> RecoverAllMats; private static readonly ConfigEntry<bool> BuildFromAttachedCart; public static readonly ConfigEntry<bool> DoorSyncMirrored; public static readonly ConfigEntry<bool> DoorIronGateBeam; public static readonly ConfigEntry<bool> ContainerOpenAttached; public static readonly ConfigEntry<int> ContainerOpenAttachedMaxDistance; public static readonly ConfigEntry<bool> ContainerOpenCraft; public static readonly ConfigEntry<bool> ContainerRenameForVehicle; public static readonly ConfigEntry<StringList> ContainersIgnored; public static readonly ConfigEntry<bool> StationContainerOpen; public static readonly ConfigEntry<bool> StationContainerOpenPlayer; public static readonly ConfigEntry<StringList> StationsIgnored; public static readonly ConfigEntry<float> StationContainerRange; public static readonly ConfigEntry<float> StationExtensionDistanceScale; public static readonly ConfigEntry<bool> StationContainerHighlight; public static readonly ConfigEntry<bool> RotationAngleChange; public static readonly ConfigEntry<StringList> RotationSegments; public static readonly ConfigEntry<KeyCode> HammerKey; public static readonly ConfigEntry<bool> BuildOnScenery; public static readonly ConfigEntry<bool> BuildOnSceneryNoTreeSupport; public static readonly ConfigEntry<StringList> BuildOnSceneryPrefabs; public static readonly ConfigEntry<StringList> NoSupportPrefabs; public static readonly ConfigEntry<StringList> NoBuildLocations; public static readonly ConfigEntry<float> NoBuildLocationsRadius; public static bool CanBuildFromCart { get { if (BuildFromAttachedCart.Value) { return !InventoryGui.IsVisible(); } return false; } } static Configs() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown //IL_008c: Expected O, but got Unknown //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Expected O, but got Unknown //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Expected O, but got Unknown //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Expected O, but got Unknown //IL_02e5: Expected O, but got Unknown //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Expected O, but got Unknown //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Expected O, but got Unknown //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Expected O, but got Unknown //IL_0341: Expected O, but got Unknown //IL_0387: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Expected O, but got Unknown //IL_0397: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Expected O, but got Unknown //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Expected O, but got Unknown //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Expected O, but got Unknown //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Expected O, but got Unknown //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03ce: Expected O, but got Unknown //IL_03ce: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Expected O, but got Unknown //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Expected O, but got Unknown //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Expected O, but got Unknown //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Expected O, but got Unknown //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Expected O, but got Unknown //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Expected O, but got Unknown //IL_0410: Unknown result type (might be due to invalid IL or missing references) //IL_041b: Expected O, but got Unknown //IL_041b: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Expected O, but got Unknown //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Expected O, but got Unknown //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_043c: Expected O, but got Unknown //IL_043c: Unknown result type (might be due to invalid IL or missing references) //IL_0447: Expected O, but got Unknown //IL_0447: Unknown result type (might be due to invalid IL or missing references) //IL_0452: Expected O, but got Unknown //IL_0452: Unknown result type (might be due to invalid IL or missing references) //IL_045d: Expected O, but got Unknown //IL_045d: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Expected O, but got Unknown //IL_048b: Expected O, but got Unknown //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_0495: Unknown result type (might be due to invalid IL or missing references) //IL_04a0: Expected O, but got Unknown //IL_04a0: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Expected O, but got Unknown //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04b6: Expected O, but got Unknown //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_04c1: Expected O, but got Unknown //IL_04c1: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: Expected O, but got Unknown //IL_04cc: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Expected O, but got Unknown //IL_04d8: Expected O, but got Unknown AllowTorchWithHammer = Config.Define<bool>(true, "General", "Allow Torch With Hammer", true, "A torch can be equipped in the offhand while using the Hammer.\r\n(Vanilla: false)"); BuildFromAttachedCart = Config.Define<bool>(true, "General", "Build From Attached Cart", true, "Use building materials directly from the attached cart.\r\n[NOTE: Materials are consumed from the player's inventory before the cart's inventory.]\r\n(Vanilla: false)"); ShowSnapIcon = Config.Define<bool>(true, "General", "Show Snapping Icon", true, "Show snapping icon in the build HUD in all input modes, not just gamepad console 1 or 2.\r\n(Vanilla: false)"); StringList val = new StringList(); ((List<string>)val).Add("piece_sharpstakes"); ((List<string>)val).Add("piece_dvergr_sharpstakes"); ((List<string>)val).Add("piece_stakewall_blackwood"); RecoverAllMats = Config.Define<StringList>(true, "General", "Recover All Mats", val, "Comma separated list of pieces that will drop all materials when destroyed. (Vanilla: blank)\r\n[logout required for changes to take effect]"); ResetBuildCursorRotation = Config.Define<bool>(true, "General", "Reset Build Cursor Rotation", true, "The rotation angle of the build cursor resets to face the camera when not near any workstations.\r\n[Has no effect if nocost mode is active]\r\n[This is helpful in nomap games so that the piece can not be used to deduce orientation]"); PavedRoadNoDeform = Config.Define<bool>(false, "General", "Paved Road - No Deform", true, "The Paved Road tool does not modify the terrain."); PavedRoadNoDeform.SettingChanged += delegate { PavedRoadTool.UpdateTool(); }; DoorSyncMirrored = Config.Define<bool>(true, "Doors", "Double Door Synchronize", true, "Synchronize mirrored double doors so they open and close together."); DoorIronGateBeam = Config.Define<bool>(true, "Doors", "Show Iron Beam", false, "Display the vertical iron beam on the frame of the \"Iron Gate\" build piece. This beam can obstruct the doorway when placing double doors.\r\n[restart required for changes to take effect]\r\n(vanilla: true)"); ContainerRenameForVehicle = Config.Define<bool>(true, "Containers", "Rename For Vechicles", true, "Rename open containers for vehicles in the inventory UI so that it matches the vehicle name, not \"Storage\"\r\nFor example the opened Cart storage would be \"Cart\", the Karve storage would be Karve.\r\nThis makes it easier to discern what you have opened when using automatic opening.\r\nThis does NOT change the hovertext, it still says \"Storage\" on the hovertext.\r\nOnly the inventory UI is changed to reflect the vehicle name of the accessed Storage."); ContainerOpenCraft = Config.Define<bool>(true, "Containers", "Craft From Open Containers", true, "Craft directly from open containers.\r\n[NOTE: Materials are consumed from the player's inventory before they are consumed from the container's inventory.]\r\n(Vanilla: false)"); ContainerOpenAttached = Config.Define<bool>(true, "Containers", "Open Attached", true, "When opening the inventory UI automatically open attached vehicle containers such as carts or ships when captain."); ContainerOpenAttachedMaxDistance = Config.Define<int>(true, "Containers", "Open Attached - Max Distance", 3, Config.AcceptRange<int>(3, 50), "Any attached containers beyond this distance will not auto-open.\r\nExamples:\r\n- Carts only, no ships: 3 (default)\r\n- Carts and Karve: 4\r\n- Carts, Karve, Longship: 12\r\n- Everything: 20\r\nYou can dial in the distance as needed for any custom requirements."); ContainersIgnored = Config.Define<StringList>(true, "Containers", "Ignored Containers", StringList.Empty, "Containers in this list are not auto-opened."); StationContainerOpen = Config.Define<bool>(true, "Crafting Stations", "Open Closest Container", true, "When using a crafting station open the closest container. "); StationContainerOpenPlayer = Config.Define<bool>(false, "Crafting Stations", "Open Closest To Player", true, "When \"" + ((ConfigEntryBase)StationContainerOpen).Definition.Key + "\" is true: \r\nUse the player's position to find the closest container.\r\nIf none are found, then use the station's position to look for a nearby container.\r\nIf this is false always uses the station's position, never the player's."); StationContainerRange = Config.Define<float>(true, "Crafting Stations", "Station Container Range", 2.5f, Config.AcceptRange<float>(1f, 10f), "Search distance when finding the closest container."); StationContainerHighlight = Config.Define<bool>(false, "Crafting Stations", "Station Container Highlight", true, "Highlight the container when it is opened from the crafting station."); StationsIgnored = Config.Define<StringList>(true, "Crafting Stations", "Stations Ignored", StringList.Empty, "List of crafting station prefab names that will not attempt to open nearby containers when used."); StationExtensionDistanceScale = Config.Define<float>(true, "Crafting Stations", "Station Extension Distance Scale", 1f, Config.AcceptRange<float>(1f, 3f), "Multiplier for max distance that workstation extensions can be spread out. (Vanilla: 1)\r\nLarger values allow extensions to be further away from the workstation. More elbow room."); RotationAngleChange = Config.Define<bool>(true, "Input", "Rotation Angle Change", true, "Adjust rotation segments for smoother curves.\r\nEquip your hammer then press:\r\nKeyboard: Press LeftShift + RightArrow to cycle modes.\r\nGamepad: Press Alt Interact + D-Pad Right to cycle modes."); StringList val2 = new StringList(); ((List<string>)val2).Add("16:Default"); ((List<string>)val2).Add("20:Advanced"); ((List<string>)val2).Add("32:Expert"); RotationSegments = Config.Define<StringList>(true, "Input", "Rotation Segments", val2, "Available rotation segments that can be selected.\r\n[CAUTION: adding to many segments will make distinguishing the angles very difficult since you are slicing\r\na circle and the more segments you have the more subtle the distinction is between each segment.\r\nThe pie slices get smaller, it gets harder to tell what angle it's going to snap at]"); HammerKey = Config.Define<KeyCode>(false, "Input", "Hammer Hotkey", (KeyCode)98, "Put your hammer anywhere in your inventory. This frees up a slot on your hotbar.\r\nWhen pressed it searches your inventory for your highest level Hammer and equips it.\r\nPress again to unequip. Press and hold to quick select repair. \r\nGamepad: Hold D-Pad Down to equip your hammer. Hold again while hammer equipped to toggle repair mode.\r\n[restart required for changes to take effect]"); StringList val3 = new StringList(); ((List<string>)val3).Add("sign"); ((List<string>)val3).Add("piece_shieldgenerator"); ((List<string>)val3).Add("piece_beehive"); NoSupportPrefabs = Config.Define<StringList>(true, "Structure", "No Support Prefabs", val3, "List of prefabs which will have support removed, nothing can be attached to them."); BuildOnScenery = Config.Define<bool>(true, "Structure", "Build on Scenery", false, "The player is not able to attach construction pieces to the sides of scenery.\r\nIt requires a flatter surface. Can no longer stick things to the sides of rocks or trees.\r\n(Unless the piece is on the exception list)\r\nThis encourages the player to build using materials available from the ground up.\r\nEnemeies can destroy the foundations of their constructions.\r\n(Vanilla: true)"); BuildOnSceneryNoTreeSupport = Config.Define<bool>(true, "Structure", "Build on Scenery - No Tree Support", false, "Trees do not provide support. Anything attached to a tree will collapse.\r\n[This encourages the player to build on the ground instead of in trees where monsters can not attack them.]\r\n[DANGER: Enabling this on an existing world with construction supported only by trees will cause it to collapse!]\r\n(Vanilla: false)"); StringList val4 = new StringList(); ((List<string>)val4).Add("sign"); ((List<string>)val4).Add("itemstand"); ((List<string>)val4).Add("piece_beehive"); ((List<string>)val4).Add("piece_walltorch"); ((List<string>)val4).Add("piece_dvergr_lantern"); ((List<string>)val4).Add("piece_brazierceiling01"); ((List<string>)val4).Add("piece_banner01"); ((List<string>)val4).Add("piece_banner02"); ((List<string>)val4).Add("piece_banner03"); ((List<string>)val4).Add("piece_banner04"); ((List<string>)val4).Add("piece_banner05"); ((List<string>)val4).Add("piece_banner06"); ((List<string>)val4).Add("piece_banner07"); ((List<string>)val4).Add("piece_banner08"); ((List<string>)val4).Add("piece_banner09"); ((List<string>)val4).Add("piece_banner10"); ((List<string>)val4).Add("piece_banner11"); ((List<string>)val4).Add("piece_cloth_hanging_door"); ((List<string>)val4).Add("piece_cloth_hanging_door_blue"); ((List<string>)val4).Add("piece_cloth_hanging_door_blue2"); BuildOnSceneryPrefabs = Config.Define<StringList>(true, "Structure", "Build on Scenery - Prefabs", val4, "Exception list of prefabs that can be attached to scenery when " + ((ConfigEntryBase)BuildOnScenery).Definition.Key + " is false.\r\nNOTE: They will not be able to support other pieces attached to them."); StringList val5 = new StringList(); ((List<string>)val5).Add("Eikthyrnir"); ((List<string>)val5).Add("GDKing"); ((List<string>)val5).Add("Bonemass"); ((List<string>)val5).Add("Dragonqueen"); ((List<string>)val5).Add("GoblinKing"); ((List<string>)val5).Add("FaderLocation"); StringList val6 = val5; NoBuildLocations = Config.Define<StringList>(true, "Structure", "No Build Locations", val6, "List of locations that prohibit building.\r\nDefaults include Bonemass to prevent player cheesing the boss fight by standing on top of the boss alter.\r\nAll other boss alters included by default for safety and completeness.\r\n[leave the area for changes to take effect]"); NoBuildLocationsRadius = Config.Define<float>(true, "Structure", "No Build Locations Radius", 25f, Config.AcceptRange<float>(0.1f, 200f), "Distance around No Build Locations that building is prohibited."); } public static HelpInfo GetHelpInfo() { //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Expected O, but got Unknown StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(HelpInfo.Format<KeyCode>(HammerKey, true, true, true)); if (AllowTorchWithHammer.Value) { stringBuilder.AppendLine(HelpInfo.Format<bool>(AllowTorchWithHammer, false, true, true)); } if (PavedRoadNoDeform.Value) { stringBuilder.AppendLine(HelpInfo.Format<bool>(PavedRoadNoDeform, false, true, true)); } if (ContainerOpenCraft.Value) { stringBuilder.AppendLine(HelpInfo.Format<bool>(ContainerOpenCraft, false, true, true)); } if (BuildFromAttachedCart.Value) { stringBuilder.AppendLine(HelpInfo.Format<bool>(BuildFromAttachedCart, false, true, true)); } if (StationContainerOpen.Value) { stringBuilder.AppendLine(HelpInfo.Format<bool>(StationContainerOpen, false, true, true)); } if (!BuildOnScenery.Value) { stringBuilder.AppendLine(HelpInfo.Format<bool>(BuildOnScenery, false, true, true)); } if (BuildOnSceneryNoTreeSupport.Value) { stringBuilder.AppendLine(HelpInfo.Format<bool>(BuildOnSceneryNoTreeSupport, false, true, true)); } if (ResetBuildCursorRotation.Value) { stringBuilder.AppendLine(HelpInfo.Format<bool>(ResetBuildCursorRotation, false, true, true)); } if (RotationAngleChange.Value && ((List<string>)(object)RotationSegments.Value).Count > 0) { stringBuilder.AppendLine(HelpInfo.Format<bool>(RotationAngleChange, false, true, false)); } return new HelpInfo("Construction", stringBuilder.ToString()); } } internal static class Inputs { public static readonly ActionString Build = ControlInputs.Create("$hud_build $radial_hold"); public static readonly ActionString Repair = ControlInputs.Create("$hud_repair $radial_hold"); public static void Register() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) Build.AddButton(Configs.HammerKey.Value, false, false, false, 0f, 0f); Build.AddButton((GamepadInput)3, false, true, false, 0f, 0f); Repair.AddButton(Configs.HammerKey.Value, false, false, false, 0f, 0f); Repair.AddButton((GamepadInput)3, false, true, false, 0f, 0f); } } [BepInPlugin("ZenDragon.ZenConstruction", "ZenConstruction", "1.3.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class Plugin : ZenMod<Plugin> { public const string PluginGUID = "ZenDragon.ZenConstruction"; public const string PluginName = "ZenConstruction"; public const string PluginVersion = "1.3.1"; protected override void Setup() { ZenMod.RequireGamepadRemap = true; base.RegisterInputs += Inputs.Register; base.ConfigSync += OnConfigSync; } private static void OnConfigSync() { Structure.SetupPrefabs(); RecoverAllMats.SetupPrefabs(); DoorRules.SetupPrefabs(); } protected override void TitleScene(bool isFirstBoot) { } protected override void HotRestore() { DoorRules.HotRestore(); } protected override void WorldStart() { QuickSelectBuild.CreateKeyHints(); PavedRoadTool.UpdateTool(); } protected override void Shutdown() { } private void Update() { if (ZenMod<Plugin>.Initialized && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { QuickSelectBuild.HandleInput(); BuildRotation.HandleInput(); } } protected override HelpInfo? GetHelpInfo() { return Configs.GetHelpInfo(); } } } namespace ZenConstruction.Section { public static class BuildRotation { [HarmonyPatch] [HarmonyPriority(0)] private static class SegmentRandomization { [UsedImplicitly] private static IEnumerable<MethodBase> TargetMethods() { return new <>z__ReadOnlyArray<MethodBase>(new MethodBase[2] { AccessTools.DeclaredMethod(typeof(Player), "SetupPlacementGhost", (Type[])null, (Type[])null), AccessTools.DeclaredMethod(typeof(Player), "PlacePiece", (Type[])null, (Type[])null) }); } [UsedImplicitly] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> codes) { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Random), "Range", new Type[2] { typeof(int), typeof(int) }, (Type[])null); Func<int, int, int> func = RandomRangeIntercept; return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)func.Method); static int RandomRangeIntercept(int min, int maxExclusive) { int num = Mathf.RoundToInt(360f / Player.m_localPlayer.m_placeRotationDegrees); return Random.Range(min, num); } } } private static int _currentIndex; public static void HandleInput() { if (Configs.RotationAngleChange.Value && UI.IsBuildModeActive && HumanoidExt.IsUsing((Humanoid)(object)Player.m_localPlayer, "Hammer", false)) { if (ZInput.GetKey((KeyCode)304, true) && ZInput.GetKeyDown((KeyCode)275, true)) { SetNextBuildRotation(); } if (ZInput.GetButton(ControlInputs.JoyAlt) && ZInput.GetButtonDown("JoyDPadRight")) { SetNextBuildRotation(); } } } private static void SetNextBuildRotation() { Dictionary<string, string> dictionary = Configs.RotationSegments.Value.ToDictionary(':'); List<(int, string)> list = new List<(int, string)>(); foreach (string key in dictionary.Keys) { if (!int.TryParse(key, out var result) || result < 2) { Logging<Plugin>.Error((object)("Ignoring invalid rotation segments in configs: " + key), (ushort)0); } else { list.Add((result, dictionary[key])); } } list.Sort(); if (list.Count == 0) { Logging<Plugin>.Error((object)"No rotation segments defined.", (ushort)0); return; } _currentIndex++; _currentIndex %= list.Count; (int, string) tuple = list[_currentIndex]; string text = StringExt.Localize("$msg_build_rotation", new string[2] { tuple.Item2, tuple.Item1.ToString() }); Player.m_localPlayer.m_placeRotationDegrees = 360f / (float)tuple.Item1; ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null); } } [HarmonyPatch] internal static class ContainerVehicle { private static Component? _attachedComponent; public static bool IsAttached() { return Object.op_Implicit((Object)(object)_attachedComponent); } public static bool IsAttached(out Vagon cart) { Component? attachedComponent = _attachedComponent; return Object.op_Implicit((Object)(object)(cart = (Vagon)(object)((attachedComponent is Vagon) ? attachedComponent : null))); } public static bool IsAttached(out Ship ship) { Component? attachedComponent = _attachedComponent; return Object.op_Implicit((Object)(object)(ship = (Ship)(object)((attachedComponent is Ship) ? attachedComponent : null))); } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "StartDoodadControl")] private static void Player_StartDoodadControl(Player __instance) { IDoodadController doodadController = __instance.GetDoodadController(); if (doodadController != null && doodadController.IsValid()) { _attachedComponent = doodadController.GetControlledComponent(); } else { _attachedComponent = null; } } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "StopDoodadControl")] private static void Player_StopDoodadControl(Player __instance) { _attachedComponent = null; } [HarmonyPostfix] [HarmonyPatch(typeof(Vagon), "AttachTo")] private static void Vagon_AttachTo(Vagon __instance) { if (PlayerExt.IsReady(Player.m_localPlayer) && __instance.IsAttached((Character)(object)Player.m_localPlayer)) { _attachedComponent = (Component?)(object)__instance; } } [HarmonyPrefix] [HarmonyPatch(typeof(Vagon), "Detach")] private static void Vagon_Detach(Vagon __instance) { if (!PlayerExt.IsReady(Player.m_localPlayer) || __instance.IsAttached((Character)(object)Player.m_localPlayer)) { _attachedComponent = null; } } } [HarmonyPatch] internal static class ContainerCraft { [HarmonyPatch] private static class CheckRequirements { [HarmonyPatch(typeof(Player), "HaveRequirementItems")] private static class PlayerHaveRequirementItems { [UsedImplicitly] private static void Prefix(Recipe piece) { _isOneIngredient = piece.m_requireOnlyOneIngredient; } [UsedImplicitly] private static void Postfix() { _isOneIngredient = false; } } private static bool _isOneIngredient; [HarmonyTranspiler] [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] private static IEnumerable<CodeInstruction> Player_HaveRequirements_Transpiler(IEnumerable<CodeInstruction> codes) { return Inventory_CountItems(codes); } [HarmonyTranspiler] [HarmonyPatch(typeof(Player), "HaveRequirementItems")] private static IEnumerable<CodeInstruction> Player_HaveRequirementItems_Transpiler(IEnumerable<CodeInstruction> codes) { return Inventory_CountItems(codes); } [HarmonyTranspiler] [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] private static IEnumerable<CodeInstruction> InventoryGui_SetupRequirement_Transpiler(IEnumerable<CodeInstruction> codes) { return Inventory_CountItems(codes); } private static IEnumerable<CodeInstruction> Inventory_CountItems(IEnumerable<CodeInstruction> codes) { MethodInfo methodInfo = AccessTools.Method(typeof(Inventory), "CountItems", (Type[])null, (Type[])null); Func<Inventory, string, int, bool, int> func = CountItems_Intercept; return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)func.Method); } private static int CountItems_Intercept(Inventory playerInv, string name, int quality, bool matchWorldLevel) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) int num = playerInv.CountItems(name, quality, matchWorldLevel); if (!Configs.ContainerOpenCraft.Value && !Configs.CanBuildFromCart) { return num; } if (!_isOneIngredient) { Recipe recipe = ((RecipeDataPair)(ref InventoryGui.instance.m_selectedRecipe)).Recipe; if (recipe == null || !recipe.m_requireOnlyOneIngredient) { if (ContainerInventory == null) { return num; } int num2 = ContainerInventory.CountItems(name, quality, matchWorldLevel); bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(29, 3, ref flag); if (flag) { val.AppendLiteral("Items "); val.AppendFormatted(name); val.AppendLiteral(" Player: "); val.AppendFormatted<int>(num); val.AppendLiteral(" + Container: "); val.AppendFormatted<int>(num2); } Logging<Plugin>.Debug(val, 0); return num + num2; } } return num; } } private static Inventory? ContainerInventory { get { Container val = InventoryGui.instance.m_currentContainer; if (!Object.op_Implicit((Object)(object)val) && Configs.CanBuildFromCart) { val = (ContainerVehicle.IsAttached(out Vagon cart) ? cart.m_container : null); } if (!Object.op_Implicit((Object)(object)val)) { return null; } return val.GetInventory(); } } [HarmonyTranspiler] [HarmonyPatch(typeof(Player), "ConsumeResources")] private static IEnumerable<CodeInstruction> Player_ConsumeResources(IEnumerable<CodeInstruction> codes) { MethodInfo methodInfo = AccessTools.Method(typeof(Inventory), "RemoveItem", new Type[4] { typeof(string), typeof(int), typeof(int), typeof(bool) }, (Type[])null); Action<Inventory, string, int, int, bool> action = RemoveItem_Intercept; return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)action.Method); } private static void RemoveItem_Intercept(Inventory playerInv, string name, int amount, int itemQuality, bool worldLevelBased) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) if (!Configs.ContainerOpenCraft.Value && !Configs.CanBuildFromCart) { playerInv.RemoveItem(name, amount, itemQuality, worldLevelBased); return; } bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(33, 2, ref flag); if (flag) { val.AppendLiteral("Removing "); val.AppendFormatted(name); val.AppendLiteral(" x"); val.AppendFormatted<int>(amount); val.AppendLiteral(" from player inventory"); } Logging<Plugin>.Info(val, 0); int num = playerInv.CountItems(name, itemQuality, worldLevelBased); playerInv.RemoveItem(name, amount, itemQuality, worldLevelBased); int num2 = amount - num; if (num2 > 0 && ContainerInventory != null) { val = new InterpolatedString<Plugin>(26, 2, ref flag); if (flag) { val.AppendLiteral("Removing "); val.AppendFormatted(name); val.AppendLiteral(" x"); val.AppendFormatted<int>(num2); val.AppendLiteral(" from container"); } Logging<Plugin>.Info(val, 0); ContainerInventory.RemoveItem(name, num2, itemQuality, worldLevelBased); } } } [HarmonyPatch] internal static class ContainerRename { private static string? _containerName; [HarmonyPostfix] [HarmonyPatch(typeof(InventoryGui), "Show")] private static void InventoryGui_Show(InventoryGui __instance, Container? container) { _containerName = null; if (Configs.ContainerRenameForVehicle.Value && Object.op_Implicit((Object)(object)container) && Object.op_Implicit((Object)(object)container.m_nview) && (Object.op_Implicit((Object)(object)((Component)container.m_nview).GetComponent<Vagon>()) || Object.op_Implicit((Object)(object)((Component)container.m_nview).GetComponent<Ship>()))) { Piece component = ((Component)container.m_nview).GetComponent<Piece>(); if (Object.op_Implicit((Object)(object)component)) { _containerName = StringExt.Localize(component.m_name); } } } [HarmonyPostfix] [HarmonyPatch(typeof(InventoryGui), "UpdateContainer")] private static void InventoryGui_UpdateContainer(InventoryGui __instance) { if (_containerName != null) { __instance.m_containerName.text = _containerName; } } } [HarmonyPatch] internal static class ContainerRules { private static readonly string[] AlwaysIgnoredContainers = new string[4] { "itemstand", "itemstandh", "ArmorStand", "piece_beehive" }; [HarmonyPrefix] [HarmonyPatch(typeof(InventoryGui), "Show")] [HarmonyPriority(100)] private static void InventoryGui_Show(InventoryGui __instance, Container? container) { if (Object.op_Implicit((Object)(object)container)) { if (Configs.ContainerOpenCraft.Value) { InventoryGui.instance.m_currentContainer = container; } } else { Timing.EndOfFrame((MonoBehaviour)(object)__instance, (Action)TryOpenAutomaticContainers); } } private static void TryOpenAutomaticContainers() { if (TryGetStationContainer(out Container container) || TryGetAttachedContainer(out container)) { Open(container); } } private static void Open(Container container) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(16, 1, ref flag); if (flag) { val.AppendLiteral("Open container: "); ZNetView nview = container.m_nview; val.AppendFormatted(((nview != null) ? nview.GetPrefabName() : null) ?? ((Object)container).name); } Logging<Plugin>.Info(val, 0); container.Interact((Humanoid)(object)Player.m_localPlayer, false, false); } private static bool TryGetAttachedContainer(out Container container) { container = null; if (!Configs.ContainerOpenAttached.Value) { return false; } Container val = null; Ship ship; if (ContainerVehicle.IsAttached(out Vagon cart)) { val = cart.m_container; } else if (ContainerVehicle.IsAttached(out ship)) { val = ((Component)ship).GetComponentInChildren<Container>(); } if (!Object.op_Implicit((Object)(object)val) || val.IsInUse()) { return false; } container = val; return true; } private static bool TryGetStationContainer(out Container container) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) container = null; if (!Configs.StationContainerOpen.Value) { return false; } CraftingStation currentStation = Player.m_localPlayer.m_currentStation; if (!Object.op_Implicit((Object)(object)currentStation)) { return false; } if (Object.op_Implicit((Object)(object)((Component)currentStation).GetComponentInChildren<Container>())) { bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(24, 1, ref flag); if (flag) { val.AppendFormatted(currentStation.GetHoverName()); val.AppendLiteral(" has Container, ignoring"); } Logging<Plugin>.Info(val, 0); return false; } if (!Object.op_Implicit((Object)(object)currentStation.m_nview)) { return false; } if (Configs.StationsIgnored.Value.Contains(currentStation.m_nview.GetPrefabName(), true)) { return false; } container = GetClosestContainer(currentStation); if (!Object.op_Implicit((Object)(object)container)) { return false; } if (InventoryGui.instance.IsContainerOpen()) { InventoryGui.instance.CloseContainer(); } return true; } [HarmonyPostfix] [HarmonyPatch(typeof(Container), "RPC_OpenRespons")] private static void Container_RPC_OpenResponse(Container __instance, bool granted) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(16, 1, ref flag); if (flag) { val.AppendLiteral("Access granted? "); val.AppendFormatted<bool>(granted); } Logging<Plugin>.Info(val, 0); if (granted && Object.op_Implicit((Object)(object)Player.m_localPlayer.m_currentStation)) { if (Configs.StationContainerHighlight.Value) { Highlight(__instance); } if (ZInput.IsGamepadActive()) { InventoryGui.instance.SetActiveGroup(3, false); } } } private static Container? GetClosestContainer(CraftingStation station) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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) //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) Container val = (Configs.StationContainerOpenPlayer.Value ? GetNearbyContainer(((Component)Player.m_localPlayer).gameObject) : null); if (!Object.op_Implicit((Object)(object)val)) { val = GetNearbyContainer(((Component)station).gameObject); } if (Object.op_Implicit((Object)(object)val)) { bool flag = default(bool); InterpolatedString<Plugin> val2 = new InterpolatedString<Plugin>(22, 2, ref flag); if (flag) { val2.AppendLiteral("Closest container: "); val2.AppendFormatted(((Object)val).name); val2.AppendLiteral(" @ "); val2.AppendFormatted<Vector3>(MathExt.XZY(((Component)val).transform.position)); } Logging<Plugin>.Info(val2, 0); } else { Logging<Plugin>.Info("No nearby containers found", 0); } return val; static Container? GetNearbyContainer(GameObject g) { HashSet<string> ignored = ((IEnumerable<string>)Configs.ContainersIgnored.Value).Concat(AlwaysIgnoredContainers).ToHashSet(); float value = Configs.StationContainerRange.Value; return GameObjectExt.GetClosest<Container>(g, value, (Func<Container, bool>)IsValid); bool IsValid(Container c) { if (!c.IsInUse() && WardAccessExt.CanAccessWard(c, false) && Object.op_Implicit((Object)(object)c.m_nview)) { return !ignored.Contains(c.m_nview.GetPrefabName()); } return false; } } } private static void Highlight(Container container) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) Piece piece = (Object.op_Implicit((Object)(object)container.m_piece) ? container.m_piece : ((Component)container).GetComponentInParent<Piece>()); Highlight.Select(piece, false, default(Color)); Timing.When((MonoBehaviour)(object)container, (Func<bool>)IsClosed, (Action)Unselect); static bool IsClosed() { return !Object.op_Implicit((Object)(object)InventoryGui.instance.m_currentContainer); } void Unselect() { Highlight.Unselect(piece); } } [HarmonyTranspiler] [HarmonyPatch(typeof(InventoryGui), "UpdateContainer")] private static IEnumerable<CodeInstruction> InventoryGui_UpdateContainer_Transpiler(IEnumerable<CodeInstruction> codes) { FieldInfo autoCloseDistanceField = AccessTools.DeclaredField(typeof(InventoryGui), "m_autoCloseDistance"); Func<InventoryGui, float> intercept = AutoCloseDistance; return Transpilers.Manipulator(codes, (Func<CodeInstruction, bool>)((CodeInstruction c) => CodeInstructionExtensions.Is(c, OpCodes.Ldfld, (MemberInfo)autoCloseDistanceField)), (Action<CodeInstruction>)delegate(CodeInstruction c) { c.opcode = OpCodes.Call; c.operand = intercept.Method; }); static float AutoCloseDistance(InventoryGui gui) { if (!ContainerVehicle.IsAttached()) { return gui.m_autoCloseDistance; } return Configs.ContainerOpenAttachedMaxDistance.Value; } } } [HarmonyPatch] internal static class DoorRules { private static readonly List<ZNetView> DoorZNetViews = new List<ZNetView>(); private static readonly string[] IgnoreDoubleDoors = new string[2] { "wood_door", "ashwood_door" }; [HarmonyPostfix] [HarmonyPatch(typeof(Door), "Awake")] private static void Door_Awake(Door __instance) { if (Object.op_Implicit((Object)(object)__instance.m_nview)) { DoorZNetViews.Add(__instance.m_nview); } } [HarmonyPostfix] [HarmonyPatch(typeof(ZNetView), "OnDestroy")] private static void ZNetView_OnDestroy(ZNetView __instance) { DoorZNetViews.Remove(__instance); } public static void HotRestore() { Door[] array = Object.FindObjectsByType<Door>((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (Door val in array) { if (Object.op_Implicit((Object)(object)val.m_nview)) { DoorZNetViews.Add(val.m_nview); } } } public static void SetupPrefabs() { if (!Configs.DoorIronGateBeam.Value) { GameObject prefab = GlobalStatic.GetPrefab("iron_grate", false); if (Object.op_Implicit((Object)(object)prefab)) { ((Component)prefab.transform.Find("New").GetChild(0)).gameObject.SetActive(false); } } } [HarmonyPostfix] [HarmonyPatch(typeof(Door), "RPC_UseDoor")] private static void RPC_UseDoor(Door __instance, bool forward) { if (Configs.DoorSyncMirrored.Value && __instance.TryGetOtherDoor(out Door otherDoor) && otherDoor.CanInteract()) { int num = __instance.m_nview.GetZDO().GetInt(ZDOVars.s_state, 0); otherDoor.m_nview.ClaimOwnership(); otherDoor.m_nview.GetZDO().Set(ZDOVars.s_state, -num, false); otherDoor.UpdateState(); } } private static bool TryGetOtherDoor(this Door self, out Door otherDoor) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) if (StringUtils.ContainsString((IReadOnlyList<string>)IgnoreDoubleDoors, self.m_nview.GetPrefabName(), StringComparison.InvariantCulture)) { bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(22, 1, ref flag); if (flag) { val.AppendLiteral("Ignoring double door: "); val.AppendFormatted(self.m_nview.GetPrefabName()); } Logging<Plugin>.Info(val, 0); otherDoor = null; return false; } ZNetView val2 = null; float num = float.MaxValue; ZNetView nview = self.m_nview; Transform transform = ((Component)nview).transform; Vector3 position = transform.position; foreach (ZNetView doorZNetView in DoorZNetViews) { if ((Object)(object)doorZNetView == (Object)(object)nview || doorZNetView.GetPrefabName() != nview.GetPrefabName()) { continue; } Vector3 position2 = ((Component)doorZNetView).transform.position; float num2 = VectorExtensions.DistanceTo(position, position2); if (!(num2 > 2.5f) && !(num2 >= num) && !(Mathf.Abs(position2.y - position.y) > 0.5f)) { Vector3 val3 = position2 - position; val3.y = 0f; Vector3 val4 = val3; if (!(((Vector3)(ref val4)).sqrMagnitude <= 0.001f) && !(Vector3.Dot(((Vector3)(ref val4)).normalized, transform.right) > 0.5f) && !(Vector3.Angle(((Component)doorZNetView).transform.forward, -((Component)nview).transform.forward) > 45f)) { num = num2; val2 = doorZNetView; } } } return Object.op_Implicit((Object)(object)(otherDoor = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<Door>() : null))); } } [HarmonyPatch] internal static class PavedRoadTool { internal static void UpdateTool() { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) ItemDrop prefab = GlobalStatic.GetPrefab<ItemDrop>("Hoe", false); if (!Object.op_Implicit((Object)(object)prefab)) { Logging<Plugin>.Warning((object)"Hoe not found, can not update PavedRoadTool", 0); return; } PieceTable buildPieces = prefab.m_itemData.m_shared.m_buildPieces; if (!Object.op_Implicit((Object)(object)buildPieces)) { Logging<Plugin>.Warning((object)"PieceTable not found, can not update PavedRoadTool", 0); return; } GameObject val = buildPieces.m_pieces.Find((GameObject p) => ((Object)p).name == "paved_road_v2"); TerrainOp component; Piece component2; if (!Object.op_Implicit((Object)(object)val)) { Logging<Plugin>.Warning((object)"Unable to find paved_road_v2", 0); } else if (val.TryGet<TerrainOp>(out component) && val.TryGet<Piece>(out component2)) { bool flag = !Configs.PavedRoadNoDeform.Value; component.m_settings.m_smooth = flag; component2.m_allowAltGroundPlacement = flag; bool flag2 = default(bool); InterpolatedString<Plugin> val2 = new InterpolatedString<Plugin>(32, 1, ref flag2); if (flag2) { val2.AppendLiteral("Paved Road tool deform terrain: "); val2.AppendFormatted<bool>(flag); } Logging<Plugin>.Info(val2, 0); if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { Player.m_localPlayer.SetupPlacementGhost(); } } } private static bool TryGet<T>(this GameObject gameObject, out T component) where T : Component { if (gameObject.TryGetComponent<T>(ref component)) { return true; } Logging<Plugin>.Warning((object)$"Component: {typeof(T)} is missing from {((Object)gameObject).name}", 0); return false; } } [HarmonyPatch] internal static class QuickSelectBuild { private static Vector2Int? _origPieceIndex; private static bool IsUsingHammer { get { Player localPlayer = Player.m_localPlayer; object obj; if (localPlayer == null) { obj = null; } else { ItemData rightItem = ((Humanoid)localPlayer).RightItem; obj = ((rightItem != null) ? ItemDataExt.GetPrefabName(rightItem) : null); } return (string?)obj == "Hammer"; } } public static void CreateKeyHints() { KeyHint.Create((HintType)1, Inputs.Repair, 2, false); KeyHint.SetEvent((HintType)1, (Action)OnUpdateHints); } private static void OnUpdateHints() { KeyHint.SetVisible(Inputs.Repair, IsUsingHammer && (!ZInput.IsGamepadActive() || !Hud.IsPieceSelectionVisible())); KeyHint.SetVisible("Place", !Hud.IsPieceSelectionVisible()); } public static void HandleInput() { CheckRepairPressed(); CheckBuildPressed(); } private static bool IsButtonHeld(ActionString button) { if (!(ZInput.GetButtonPressedTimer(ActionString.op_Implicit(button)) >= 0.8f)) { return false; } ZInput.ResetButtonStatus(ActionString.op_Implicit(button)); return true; } private static void CheckRepairPressed() { if (IsUsingHammer && (!ZInput.IsGamepadActive() || !Hud.IsPieceSelectionVisible()) && IsButtonHeld(Inputs.Build)) { ToggleRepairTool(); } } private static void ToggleRepairTool() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (IsUsingHammer) { Player localPlayer = Player.m_localPlayer; if (_origPieceIndex.HasValue) { localPlayer.SetSelectedPiece(_origPieceIndex.Value); localPlayer.UpdatePlacementGhost(false); _origPieceIndex = null; } else { _origPieceIndex = localPlayer.m_buildPieces.GetSelectedIndex(); PlayerExt.SelectRepairTool(localPlayer); } } } private static void CheckBuildPressed() { if (!((Character)Player.m_localPlayer).TakeInput()) { return; } bool flag = (UI.IsBuildModeActive ? ZInput.GetButtonUp(ActionString.op_Implicit(Inputs.Build)) : ZInput.GetButtonDown(ActionString.op_Implicit(Inputs.Build))); if (ZInput.IsGamepadActive()) { if (Hud.IsPieceSelectionVisible() || !IsButtonHeld(Inputs.Build)) { return; } flag = true; } if (flag && !(ZInput.GetButtonLastPressedTimer(ActionString.op_Implicit(Inputs.Build)) > 0.3f)) { ItemData val = (from hammer in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems() where ItemDataExt.GetPrefabName(hammer) == "Hammer" orderby hammer.m_quality descending select hammer).FirstOrDefault(); if (val == null) { ((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_missingitem: $item_hammer", 0, (Sprite)null); } else { ToolEquip.ToggleHammer(val); } } } [HarmonyPostfix] [HarmonyPatch(typeof(Hud), "SelectPiece")] private static void Hud_SelectPiece() { _origPieceIndex = null; } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "Awake")] private static void Player_Awake(Player __instance) { if (IsUsingHammer) { PlayerExt.SelectRepairTool(__instance); ((Humanoid)__instance).HideHandItems(false, true); } } } [HarmonyPatch] internal static class BuildRotationReset { [HarmonyTranspiler] [HarmonyPatch(typeof(Player), "SetupPlacementGhost")] [HarmonyPriority(0)] private static IEnumerable<CodeInstruction> Player_SetupPlacementGhost(IEnumerable<CodeInstruction> codes) { FieldInfo from = AccessTools.DeclaredField(typeof(Piece), "m_randomInitBuildRotation"); Func<Piece, bool> to = IsRandomInitBuildRotation; return Transpilers.Manipulator(codes, (Func<CodeInstruction, bool>)((CodeInstruction c) => CodeInstructionExtensions.Is(c, OpCodes.Ldfld, (MemberInfo)from)), (Action<CodeInstruction>)delegate(CodeInstruction c) { c.opcode = OpCodes.Call; c.operand = to.Method; }); } private static bool IsRandomInitBuildRotation(Piece piece) { if (!Configs.ResetBuildCursorRotation.Value || Player.m_localPlayer.NoCostCheat()) { return piece.m_randomInitBuildRotation; } if (piece.m_randomInitBuildRotation) { return true; } if (CraftingStation.m_allStations.Any((CraftingStation station) => MathExt.DistanceToXZ((MonoBehaviour)(object)station, (MonoBehaviour)(object)Player.m_localPlayer) < station.GetStationBuildRange())) { Logging<Plugin>.Info("Crafting station found in range, rotation not changed", 0); return false; } SetPlacementRotationToFaceCamera(); return false; } private static void SetPlacementRotationToFaceCamera() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) Logging<Plugin>.Info("Rotate the piece to face the player", 0); Player localPlayer = Player.m_localPlayer; Quaternion rotation = ((Component)GameCamera.instance).transform.rotation; float num = ((Quaternion)(ref rotation)).eulerAngles.y + 180f; int num2 = Mathf.RoundToInt(360f / localPlayer.m_placeRotationDegrees); int placeRotation = Mathf.RoundToInt(num / localPlayer.m_placeRotationDegrees) % num2; localPlayer.m_placeRotation = placeRotation; } } [HarmonyPatch] internal static class ShowSnapIcon { [HarmonyPostfix] [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static void Player_AlternativePlacementActive(Player __instance, ref bool __result) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (Configs.ShowSnapIcon.Value) { if (!ZInput.IsGamepadActive()) { __result = __result || ZInput.GetButton("AltPlace"); } else if ((int)ZInput.InputLayout == 0) { __result = __result || ZInput.GetButton("JoyAltPlace"); } } } [HarmonyPostfix] [HarmonyPatch(typeof(Hud), "GetSnappingIconForPiece")] private static void Hud_GetSnappingIconForPiece(Hud __instance, Piece piece, ref Sprite? __result) { if (Object.op_Implicit((Object)(object)__result) && piece != null && piece.m_groundPiece && !piece.m_allowAltGroundPlacement) { __result = null; } } } internal static class RecoverAllMats { public static void SetupPrefabs() { foreach (string item in (List<string>)(object)Configs.RecoverAllMats.Value) { Piece prefab = GlobalStatic.GetPrefab<Piece>(item, false); if (!Object.op_Implicit((Object)(object)prefab)) { Logging<Plugin>.Error((object)("Prefab " + item + " not found"), (ushort)0); continue; } Requirement[] resources = prefab.m_resources; for (int i = 0; i < resources.Length; i++) { resources[i].m_recover = true; } } } } [HarmonyPatch] public static class Structure { internal static void SetupPrefabs() { foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if (Configs.NoSupportPrefabs.Value.Contains(((Object)prefab).name, true)) { RemoveStructureSupports(prefab); } if (!Configs.BuildOnScenery.Value && Configs.BuildOnSceneryPrefabs.Value.Contains(((Object)prefab).name, true)) { RemoveStructureSupports(prefab); } } } private static void CheckIfNoBuild(Location location) { string prefabName = Utils.GetPrefabName(((Component)location).gameObject); if (Configs.NoBuildLocations.Value.Contains(prefabName, true)) { location.m_noBuild = true; location.m_noBuildRadiusOverride = Configs.NoBuildLocationsRadius.Value; } } private static void RemoveStructureSupports(GameObject prefab) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) WearNTear val = default(WearNTear); if (prefab.TryGetComponent<WearNTear>(ref val)) { bool flag = default(bool); InterpolatedString<Plugin> val2 = new InterpolatedString<Plugin>(27, 1, ref flag); if (flag) { val2.AppendLiteral("Remove WearNTear Supports: "); val2.AppendFormatted(((Object)prefab).name); } Logging<Plugin>.Info(val2, 0); val.m_supports = false; } } private static bool IsAllowedToBuild(GameObject gameObject) { if (Configs.BuildOnScenery.Value) { return true; } if (Configs.BuildOnSceneryPrefabs.Value.Contains(Utils.GetPrefabName(((Object)gameObject).name), true)) { return true; } return false; } [HarmonyTranspiler] [HarmonyPatch(typeof(WearNTear), "UpdateSupport")] private static IEnumerable<CodeInstruction> WearNTear_UpdateSupport_Transpiler(IEnumerable<CodeInstruction> codes) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(Physics), "OverlapBoxNonAlloc", new Type[5] { typeof(Vector3), typeof(Vector3), typeof(Collider[]), typeof(Quaternion), typeof(int) }, (Type[])null); Func<Vector3, Vector3, Collider[], Quaternion, int, WearNTear, int> func = OverlapBoxNonAllocIntercept; return new CodeMatcher(codes, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Call, (object)methodInfo, (string)null) }).ThrowIfInvalid("Unable to match IL").Set(OpCodes.Call, (object)func.Method) .Insert((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldarg_0, (object)null) }) .InstructionEnumeration(); static int FilterTrees(Collider[] colliders, int count) { int result = 0; for (int i = 0; i < count; i++) { Collider val = colliders[i]; if (Object.op_Implicit((Object)(object)val) && val.enabled && !val.isTrigger && !IsTree(((Component)val).transform)) { colliders[result++] = val; } } return result; } static bool IsTree(Transform t) { if (Object.op_Implicit((Object)(object)((Component)t).GetComponentInParent<TreeBase>())) { return true; } while (true) { if (Utils.GetPrefabName(((Object)t).name).ToLower().Contains("tree")) { return true; } if (!Object.op_Implicit((Object)(object)t.parent)) { break; } t = t.parent; } return false; } static int OverlapBoxNonAllocIntercept(Vector3 center, Vector3 halfExtents, Collider[] results, Quaternion orientation, int mask, WearNTear wnt) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) int num = Physics.OverlapBoxNonAlloc(center, halfExtents, results, orientation, mask); if (Configs.BuildOnScenery.Value || IsAllowedToBuild(((Component)wnt).gameObject)) { return num; } if (!Configs.BuildOnSceneryNoTreeSupport.Value) { return num; } return FilterTrees(results, num); } } [HarmonyTranspiler] [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] private static IEnumerable<CodeInstruction> Player_UpdatePlacementGhost_Transpiler(IEnumerable<CodeInstruction> codes, ILGenerator gen) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_I4_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Stfld, (object)AccessTools.Field(typeof(Player), "m_placementStatus"), (string)null) }; Func<Vector3, Heightmap, Piece, PlacementStatus> func = PlacementStatusDefaultIntercept; CodeInstruction[] array2 = (CodeInstruction[])(object)new CodeInstruction[5] { new CodeInstruction(OpCodes.Pop, (object)null), new CodeInstruction(OpCodes.Ldloc_S, (object)(byte)4), new CodeInstruction(OpCodes.Ldloc_S, (object)(byte)6), new CodeInstruction(OpCodes.Ldloc_S, (object)(byte)5), new CodeInstruction(OpCodes.Call, (object)func.Method) }; return new CodeMatcher(codes, gen).MatchStartForward(array).ThrowIfInvalid("Unable to match IL").Advance(2) .Insert(array2) .InstructionEnumeration(); static PlacementStatus PlacementStatusDefaultIntercept(Vector3 normal, Heightmap? heightmap, Piece? piece) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (!IsAllowedToBuild(Player.m_localPlayer.m_placementGhost)) { if (!(normal.y > 0.75f)) { if (!Object.op_Implicit((Object)(object)heightmap) && !Object.op_Implicit((Object)(object)piece)) { return (PlacementStatus)1; } return (PlacementStatus)0; } return (PlacementStatus)0; } return (PlacementStatus)0; } } [HarmonyPrefix] [HarmonyPatch(typeof(StationExtension), "Awake")] private static void StationExtension_Awake(StationExtension __instance) { float value = Configs.StationExtensionDistanceScale.Value; if (value > 1f) { __instance.m_maxStationDistance *= value; } } [HarmonyPostfix] [HarmonyPatch(typeof(Location), "Awake")] private static void Location_Awake(Location __instance) { CheckIfNoBuild(__instance); } } [HarmonyPatch] internal static class ToolEquip { [HarmonyPatch(typeof(Humanoid), "EquipItem")] [HarmonyPriority(200)] private static class Humanoid_EquipItem { [UsedImplicitly] private static void Prefix(Humanoid __instance, ItemData? item, ref (ItemData? Left, ItemData? Right) __state) { __state.Left = __instance.LeftItem; __state.Right = __instance.RightItem; } [UsedImplicitly] private static void Postfix(Humanoid __instance, ItemData? item, (ItemData? Left, ItemData? Right) __state) { if (!Configs.AllowTorchWithHammer.Value || (Object)(object)Player.m_localPlayer != (Object)(object)__instance || item == null) { return; } ItemData right = __state.Right; var (left, _) = __state; if (ItemDataExt.GetPrefabName(item) == "Hammer") { EquipHammer(); } else if (ItemDataExt.IsItemType(item, (ItemType)15)) { ItemData obj = right; if (((obj != null) ? ItemDataExt.GetPrefabName(obj) : null) == "Hammer") { EquipTorchLeftHand(); } } void EquipHammer() { if (left != null && ItemDataExt.IsItemType(left, (ItemType)15)) { __instance.m_leftItem = left; } else if (right != null && ItemDataExt.IsItemType(right, (ItemType)15)) { __instance.m_leftItem = right; } if (__instance.m_leftItem != null) { __instance.m_leftItem.m_equipped = true; __instance.SetupEquipment(); } } void EquipTorchLeftHand() { __instance.m_rightItem = right; __instance.m_leftItem = item; __instance.m_leftItem.m_equipped = true; __instance.m_rightItem.m_equipped = true; __instance.SetupEquipment(); } } } private const float DefaultToolEquipDuration = 0.3f; internal const string HammerTool = "Hammer"; private static (ItemData? Left, ItemData? Right) _prevEquip; [HarmonyPostfix] [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] [HarmonyPriority(0)] private static void ObjectDB_CopyOtherDB(ObjectDB __instance) { foreach (ItemData item in from prefab in __instance.m_items select prefab.GetComponent<ItemDrop>().m_itemData into item where ItemDataExt.IsItemType(item, (ItemType)19) select item) { if (item.m_shared.m_equipDuration <= 0f) { item.m_shared.m_equipDuration = 0.3f; } Logging<Plugin>.Info(ItemDataExt.GetName(item) + " equip duration: " + item.m_shared.m_equipDuration, 0); } } internal static void ToggleHammer(ItemData hammer) { if (!(ItemDataExt.GetPrefabName(hammer) != "Hammer")) { if (hammer.m_equipped) { RestoreEquip(hammer); return; } CacheEquip(); ((Humanoid)Player.m_localPlayer).ToggleEquipped(hammer); } } private static void CacheEquip() { _prevEquip.Left = ((Humanoid)Player.m_localPlayer).LeftItem; _prevEquip.Right = ((Humanoid)Player.m_localPlayer).RightItem; } private static void RestoreEquip(ItemData hammer) { ItemData val = FindItem(_prevEquip.Right); ItemData val2 = FindItem(_prevEquip.Left); if (val != null && val2 != null) { ((Humanoid)Player.m_localPlayer).ToggleEquipped(val); ((Humanoid)Player.m_localPlayer).EquipItem(val2, true); } else if (val != null && val2 == null) { ((Humanoid)Player.m_localPlayer).ToggleEquipped((ItemData)(ItemDataExt.IsItemType(val, (ItemType)15) ? ((object)hammer) : ((object)val))); } else if (val == null && val2 != null) { ((Humanoid)Player.m_localPlayer).ToggleEquipped((ItemData)(ItemDataExt.IsItemType(val2, (ItemType)15) ? ((object)hammer) : ((object)val2))); } else if (val == null && val2 == null) { ((Humanoid)Player.m_localPlayer).ToggleEquipped(hammer); } _prevEquip = default((ItemData, ItemData)); static ItemData? FindItem(ItemData? original) { if (original != null) { return ((IEnumerable<ItemData>)((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData item) => ItemDataExt.IsEqual(item, original))); } return null; } } } } namespace ZenConstruction.Compatibility { [HarmonyPatch] internal static class Backpacks { private const string BackpacksID = "org.bepinex.plugins.backpacks"; private static bool IsModLoadedBackpacks => Chainloader.PluginInfos.ContainsKey("org.bepinex.plugins.backpacks"); [HarmonyPostfix] [HarmonyPatch(typeof(InventoryGui), "CloseContainer")] private static void InventoryGui_CloseContainer(InventoryGui __instance) { if (IsModLoadedBackpacks && InventoryGui.IsVisible()) { __instance.UpdateCraftingPanel(false); } } } } [CompilerGenerated] internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { int ICollection.Count => _items.Length; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection<T>.Count => _items.Length; T IReadOnlyList<T>.this[int index] => _items[index]; int ICollection<T>.Count => _items.Length; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyArray(T[] items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.CopyTo(Array array, int index) { ((ICollection)_items).CopyTo(array, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return ((IList)_items).Contains(value); } int IList.IndexOf(object value) { return ((IList)_items).IndexOf(value); } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return ((IEnumerable<T>)_items).GetEnumerator(); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return ((ICollection<T>)_items).Contains(item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { ((ICollection<T>)_items).CopyTo(array, arrayIndex); } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { return ((IList<T>)_items).IndexOf(item); } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } }