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 DadsQoL v1.4.0
DadsQoL.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DadsQoL.MassFarming; using HarmonyLib; using Microsoft.CodeAnalysis; using Splatform; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("DadsQoL")] [assembly: AssemblyDescription("Configurable Valheim quality-of-life features")] [assembly: AssemblyCompany("Dad_Is_Bored")] [assembly: AssemblyProduct("DadsQoL")] [assembly: AssemblyCopyright("Copyright 2026 Dad_Is_Bored")] [assembly: AssemblyFileVersion("1.4.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.4.0.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 DadsQoL { [BepInPlugin("com.dadisbored.dadsqol", "DadsQoL", "1.4.0")] public sealed class DadsQoLPlugin : BaseUnityPlugin { public const string PluginGuid = "com.dadisbored.dadsqol"; public const string PluginName = "DadsQoL"; public const string PluginVersion = "1.4.0"; internal static ConfigEntry<bool> ModEnabled; internal static ManualLogSource ModLog; internal static ConfigEntry<bool> CarryWeightEnabled; internal static ConfigEntry<float> CarryWeight; internal static ConfigEntry<bool> PickupRadiusEnabled; internal static ConfigEntry<float> PickupRadius; internal static ConfigEntry<bool> AttractFish; internal static ConfigEntry<bool> EquipmentInWaterEnabled; internal static ConfigEntry<bool> MassFarmingEnabled; internal static ConfigEntry<KeyboardShortcut> MassFarmingKeyboardShortcut; internal static ConfigEntry<KeyboardShortcut> MassFarmingControllerShortcut; internal static ConfigEntry<float> MassHarvestRadius; internal static ConfigEntry<int> PlantGridWidth; internal static ConfigEntry<int> PlantGridLength; internal static ConfigEntry<bool> IgnorePlantingStamina; internal static ConfigEntry<bool> IgnorePlantingDurability; internal static ConfigEntry<bool> CenterPlantingGridWidth; internal static ConfigEntry<bool> CenterPlantingGridLength; internal static ConfigEntry<bool> EternalFuelEnabled; internal static ConfigEntry<bool> EternalCampfires; internal static ConfigEntry<bool> EternalBonfires; internal static ConfigEntry<bool> EternalHearths; internal static ConfigEntry<bool> EternalSconces; internal static ConfigEntry<bool> EternalStandingIronTorches; internal static ConfigEntry<bool> EternalStandingWoodTorches; internal static ConfigEntry<bool> EternalStandingGreenTorches; internal static ConfigEntry<bool> EternalStandingBlueTorches; internal static ConfigEntry<bool> EternalStandingBraziers; internal static ConfigEntry<bool> EternalHangingBraziers; internal static ConfigEntry<bool> EternalJackOTurnips; internal static ConfigEntry<bool> EternalStoneOvens; internal static ConfigEntry<bool> EternalHotTubs; internal static ConfigEntry<bool> EternalSmelters; internal static ConfigEntry<bool> EternalBlastFurnaces; internal static ConfigEntry<bool> EternalFrostFoundries; internal static ConfigEntry<bool> EternalEitrRefineries; internal static ConfigEntry<string> EternalCustomPrefabs; internal static ConfigEntry<bool> SharedRecipes; internal static ConfigEntry<bool> AutomaticMapSharing; private Harmony? _harmony; internal static bool MassFarmingActive => FeatureEnabled(MassFarmingEnabled); private void Awake() { //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_056c: Unknown result type (might be due to invalid IL or missing references) //IL_0576: Expected O, but got Unknown ModLog = ((BaseUnityPlugin)this).Logger; ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Enable or disable every DadsQoL feature."); CarryWeightEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Carry Weight", "Enabled", true, "Enable the configured base carry weight."); CarryWeight = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Carry Weight", "Base Carry Weight", 5000f, "Base carry weight before food, equipment, status-effect, and world modifiers. Vanilla is 300."); PickupRadiusEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Pickup Radius", "Enabled", true, "Enable the configured automatic pickup radius."); PickupRadius = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Pickup Radius", "Radius", 6f, "Automatic pickup radius in meters. Vanilla is 2."); AttractFish = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Pickup Radius", "Attract Fish", false, "Allow automatic pickup to pull fish toward the player. Turn off to keep fish from following behind you; fish can still be picked up manually."); EquipmentInWaterEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Equipment In Water", "Enabled", true, "Allow tools, weapons, shields, bows, and other hand equipment to remain usable while swimming."); MassFarmingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Mass Farming", "Enabled", true, "Enable mass harvesting and grid planting."); MassFarmingKeyboardShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("5 - Mass Farming", "Keyboard Shortcut", new KeyboardShortcut((KeyCode)304, Array.Empty<KeyCode>()), "Hold while harvesting or planting to use mass farming."); MassFarmingControllerShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("5 - Mass Farming", "Controller Shortcut", new KeyboardShortcut((KeyCode)334, Array.Empty<KeyCode>()), "Hold while harvesting or planting to use mass farming with a controller."); MassHarvestRadius = ((BaseUnityPlugin)this).Config.Bind<float>("5 - Mass Farming", "Harvest Radius", 5f, "Radius in meters for harvesting matching pickables and extracting nearby beehives."); PlantGridWidth = ((BaseUnityPlugin)this).Config.Bind<int>("5 - Mass Farming", "Plant Grid Width", 5, "Number of plants across the grid."); PlantGridLength = ((BaseUnityPlugin)this).Config.Bind<int>("5 - Mass Farming", "Plant Grid Length", 5, "Number of plants along the grid."); IgnorePlantingStamina = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Mass Farming", "Ignore Planting Stamina", false, "Do not consume stamina for the additional plants."); IgnorePlantingDurability = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Mass Farming", "Ignore Planting Durability", false, "Do not consume cultivator durability for the additional plants."); CenterPlantingGridWidth = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Mass Farming", "Center Grid Width", true, "Center the grid across the first plant instead of extending to one side."); CenterPlantingGridLength = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Mass Farming", "Center Grid Length", true, "Center the grid along the first plant instead of extending forward."); EternalFuelEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Enabled", true, "Keep selected fuel-burning pieces fully fueled."); EternalCampfires = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Campfires", true, "Keep campfires fueled."); EternalBonfires = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Bonfires", true, "Keep bonfires fueled."); EternalHearths = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Hearths", true, "Keep hearths fueled."); EternalSconces = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Sconces", true, "Keep wall sconces fueled."); EternalStandingIronTorches = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Standing Iron Torches", true, "Keep standing iron torches fueled."); EternalStandingWoodTorches = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Standing Wood Torches", true, "Keep standing wood torches fueled."); EternalStandingGreenTorches = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Standing Green Torches", true, "Keep green-burning standing torches fueled."); EternalStandingBlueTorches = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Standing Blue Torches", true, "Keep blue-burning standing torches fueled."); EternalStandingBraziers = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Standing Braziers", true, "Keep standing braziers fueled."); EternalHangingBraziers = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Hanging Braziers", true, "Keep hanging braziers fueled."); EternalJackOTurnips = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Jack-o-turnips", true, "Keep jack-o-turnips fueled."); EternalStoneOvens = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Stone Ovens", true, "Keep stone ovens fueled."); EternalHotTubs = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Hot Tubs", true, "Keep hot tubs fueled."); EternalSmelters = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Smelters", false, "Keep smelters fueled."); EternalBlastFurnaces = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Blast Furnaces", false, "Keep blast furnaces fueled."); EternalFrostFoundries = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Frost Foundries", false, "Keep frost foundries fueled."); EternalEitrRefineries = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Eternal Fuel", "Eitr Refineries", false, "Keep eitr refineries fueled."); EternalCustomPrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Eternal Fuel", "Custom Prefabs", string.Empty, "Comma-separated exact prefab names whose Fireplace, CookingStation, or Smelter fuel must remain full."); SharedRecipes = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Multiplayer", "Shared Recipes", true, "Share discovered crafting recipes with everyone in the world."); AutomaticMapSharing = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Multiplayer", "Automatic Map Sharing", true, "Automatically share explored map areas with everyone in the world."); ModEnabled.SettingChanged += OnPickupSettingChanged; PickupRadiusEnabled.SettingChanged += OnPickupSettingChanged; PickupRadius.SettingChanged += OnPickupSettingChanged; _harmony = new Harmony("com.dadisbored.dadsqol"); _harmony.PatchAll(typeof(DadsQoLPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"DadsQoL 1.4.0 loaded."); } private static void OnPickupSettingChanged(object sender, EventArgs eventArgs) { if ((Object)(object)Player.m_localPlayer != (Object)null) { PlayerAwakePatch.Apply(Player.m_localPlayer); } } private void OnDestroy() { MultiplayerSharing.Reset(); MassPlantingState.DestroyGhosts(); Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void Update() { MultiplayerSharing.Update(); } internal static bool FeatureEnabled(ConfigEntry<bool> feature) { if (ModEnabled.Value) { return feature.Value; } return false; } internal static bool MassFarmingShortcutHeld() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!ShortcutHeld(MassFarmingKeyboardShortcut.Value)) { return ShortcutHeld(MassFarmingControllerShortcut.Value); } return true; } private static bool ShortcutHeld(KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey)) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { if (!Input.GetKey(modifier)) { return false; } } return true; } } [HarmonyPatch(typeof(Player), "Awake")] internal static class PlayerAwakePatch { private sealed class OriginalRange { internal float Value; } private static readonly ConditionalWeakTable<Player, OriginalRange> OriginalRanges = new ConditionalWeakTable<Player, OriginalRange>(); private static void Prefix(Player __instance) { OriginalRanges.GetValue(__instance, (Player player) => new OriginalRange { Value = player.m_autoPickupRange }); } private static void Postfix(Player __instance) { Apply(__instance); } internal static void Apply(Player player) { OriginalRange value = OriginalRanges.GetValue(player, (Player current) => new OriginalRange { Value = current.m_autoPickupRange }); player.m_autoPickupRange = (DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.PickupRadiusEnabled) ? Math.Max(0f, DadsQoLPlugin.PickupRadius.Value) : value.Value); } } [HarmonyPatch(typeof(Player), "AutoPickup")] internal static class AutoPickupCapacityPatch { private static readonly FieldRef<Player, Collider[]> PickupColliders = AccessTools.FieldRefAccess<Player, Collider[]>("m_colliders"); private static readonly FieldInfo ItemInstancesField = AccessTools.Field(typeof(ItemDrop), "s_instances"); private static readonly FieldInfo AutoPickupEnabledField = AccessTools.Field(typeof(Player), "m_enableAutoPickup"); private static Player? _remoteScanPlayer; private static int _remoteScanIndex; private static float _lastRemotePass; private static float _remoteMoveDelta; private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo overlap = AccessTools.Method(typeof(Physics), "OverlapSphereNonAlloc", new Type[4] { typeof(Vector3), typeof(float), typeof(Collider[]), typeof(int) }, (Type[])null); MethodInfo scan = AccessTools.Method(typeof(AutoPickupCapacityPatch), "ScanPickupColliders", (Type[])null, (Type[])null); foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, overlap)) { yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null); instruction.opcode = OpCodes.Call; instruction.operand = scan; } yield return instruction; } } private static int ScanPickupColliders(Vector3 position, float radius, Collider[] buffer, int mask, Player player) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (buffer == null || buffer.Length == 0) { buffer = (Collider[])(object)new Collider[100]; PickupColliders.Invoke(player) = buffer; } int num = Physics.OverlapSphereNonAlloc(position, radius, buffer, mask); while (num == buffer.Length && buffer.Length < 65536) { buffer = (Collider[])(object)new Collider[buffer.Length * 2]; PickupColliders.Invoke(player) = buffer; num = Physics.OverlapSphereNonAlloc(position, radius, buffer, mask); } if (!DadsQoLPlugin.AttractFish.Value) { int num2 = 0; for (int i = 0; i < num; i++) { Collider val = buffer[i]; if (!((Object)(object)val == (Object)null) && !IsFish(val)) { buffer[num2++] = val; } } for (int j = num2; j < num; j++) { buffer[j] = null; } num = num2; } return num; } private static bool IsFish(Collider collider) { if ((Object)(object)((Component)collider).GetComponentInParent<Fish>() != (Object)null) { return true; } ItemDrop componentInParent = ((Component)collider).GetComponentInParent<ItemDrop>(); if ((Object)(object)componentInParent != (Object)null) { return IsFish(componentInParent); } return false; } private static bool IsFish(ItemDrop item) { if ((Object)(object)((Component)item).GetComponent<Fish>() != (Object)null) { return true; } ItemData itemData = item.m_itemData; if (itemData != null && (Object)(object)itemData.m_dropPrefab != (Object)null) { return (Object)(object)itemData.m_dropPrefab.GetComponent<Fish>() != (Object)null; } return false; } private static bool Prefix(Player __instance, ref float __0, out float __state) { __state = (((Object)(object)__instance != (Object)null) ? __instance.m_autoPickupRange : 0f); if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } PlayerAwakePatch.Apply(__instance); __state = __instance.m_autoPickupRange; if (!DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.PickupRadiusEnabled)) { return true; } Inventory inventory = ((Humanoid)__instance).GetInventory(); if (inventory == null) { return true; } if (!inventory.HaveEmptySlot()) { bool flag = false; foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem?.m_shared != null && allItem.m_stack < allItem.m_shared.m_maxStackSize) { flag = true; break; } } if (!flag) { return false; } } if (__instance.m_autoPickupRange > 32f) { ScanDistantItems(__instance, inventory); __instance.m_autoPickupRange = 12f; } return true; } private static void ScanDistantItems(Player player, Inventory inventory) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013b: 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_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) if (!(bool)AutoPickupEnabledField.GetValue(null) || ((Character)player).IsTeleporting() || !(ItemInstancesField.GetValue(null) is List<ItemDrop> { Count: not 0 } list)) { return; } float unscaledTime = Time.unscaledTime; if ((Object)(object)_remoteScanPlayer != (Object)(object)player || unscaledTime < _lastRemotePass) { _remoteScanPlayer = player; _remoteScanIndex = 0; _lastRemotePass = unscaledTime; _remoteMoveDelta = Time.fixedDeltaTime; } if (_remoteScanIndex >= list.Count) { _remoteScanIndex = 0; _remoteMoveDelta = Mathf.Min(unscaledTime - _lastRemotePass, 0.6f); _lastRemotePass = unscaledTime; } Vector3 val = ((Component)player).transform.position + Vector3.up; float num = player.m_autoPickupRange * player.m_autoPickupRange; float num2 = -1f; float num3 = 0f; for (int i = 0; i < 64; i++) { if (_remoteScanIndex >= list.Count) { break; } ItemDrop val2 = list[_remoteScanIndex++]; if ((Object)(object)val2 == (Object)null || val2.m_itemData == null || !val2.m_autoPickup || (!DadsQoLPlugin.AttractFish.Value && IsFish(val2))) { continue; } Vector3 position = ((Component)val2).transform.position; Vector3 val3 = val - position; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude <= 144f || sqrMagnitude > num || val2.IsPiece() || ((Humanoid)player).HaveUniqueKey(val2.m_itemData.m_shared.m_name)) { continue; } ZNetView component = ((Component)val2).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { continue; } if (!val2.CanPickup(true)) { val2.RequestOwn(); } else { if (val2.InTar()) { continue; } val2.Load(); if (!inventory.CanAddItem(val2.m_itemData, -1)) { continue; } if (num2 < 0f) { num2 = inventory.GetTotalWeight(); num3 = player.GetMaxCarryWeight(); } if (!(num2 + val2.m_itemData.GetWeight(-1) > num3)) { float num4 = Mathf.Sqrt(sqrMagnitude); float num5 = Mathf.Min(15f * _remoteMoveDelta, num4 - 11f); if (num5 > 0f) { ((Component)val2).transform.position = position + val3 * (num5 / num4); } } } } } private static void Postfix(Player __instance, float __state) { if ((Object)(object)__instance != (Object)null) { __instance.m_autoPickupRange = __state; } } } [HarmonyPatch(typeof(Player), "GetMaxCarryWeight")] internal static class CarryWeightPatch { private static void Prefix(Player __instance, out float __state) { __state = __instance.m_maxCarryWeight; if (DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.CarryWeightEnabled)) { __instance.m_maxCarryWeight = Math.Max(0f, DadsQoLPlugin.CarryWeight.Value); } } private static void Postfix(Player __instance, float __state) { __instance.m_maxCarryWeight = __state; } } [HarmonyPatch] internal static class EquipmentInWaterPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Humanoid), "UpdateEquipment", new Type[1] { typeof(float) }, (Type[])null); yield return AccessTools.Method(typeof(Humanoid), "EquipItem", new Type[2] { typeof(ItemData), typeof(bool) }, (Type[])null); } private static void Prefix(Humanoid __instance, ref float ___m_swimTimer, out float __state) { __state = ___m_swimTimer; if (DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.EquipmentInWaterEnabled) && ((Character)__instance).IsPlayer() && ___m_swimTimer < 0.5f) { ___m_swimTimer = 0.5f; } } private static void Postfix(ref float ___m_swimTimer, float __state) { ___m_swimTimer = __state; } } internal static class EternalFuel { private sealed class CachedName { internal string Value = string.Empty; } private static readonly ConditionalWeakTable<Component, CachedName> PrefabNames = new ConditionalWeakTable<Component, CachedName>(); private static string _customPrefabSource = string.Empty; private static HashSet<string> _customPrefabs = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, Func<bool>> BuiltInPrefabs = new Dictionary<string, Func<bool>>(StringComparer.OrdinalIgnoreCase) { ["fire_pit"] = () => DadsQoLPlugin.EternalCampfires.Value, ["bonfire"] = () => DadsQoLPlugin.EternalBonfires.Value, ["hearth"] = () => DadsQoLPlugin.EternalHearths.Value, ["piece_walltorch"] = () => DadsQoLPlugin.EternalSconces.Value, ["piece_groundtorch"] = () => DadsQoLPlugin.EternalStandingIronTorches.Value, ["piece_groundtorch_wood"] = () => DadsQoLPlugin.EternalStandingWoodTorches.Value, ["piece_groundtorch_green"] = () => DadsQoLPlugin.EternalStandingGreenTorches.Value, ["piece_groundtorch_blue"] = () => DadsQoLPlugin.EternalStandingBlueTorches.Value, ["piece_brazierfloor01"] = () => DadsQoLPlugin.EternalStandingBraziers.Value, ["piece_brazierceiling01"] = () => DadsQoLPlugin.EternalHangingBraziers.Value, ["piece_jackoturnip"] = () => DadsQoLPlugin.EternalJackOTurnips.Value, ["piece_oven"] = () => DadsQoLPlugin.EternalStoneOvens.Value, ["piece_bathtub"] = () => DadsQoLPlugin.EternalHotTubs.Value, ["smelter"] = () => DadsQoLPlugin.EternalSmelters.Value, ["blastfurnace"] = () => DadsQoLPlugin.EternalBlastFurnaces.Value, ["piece_FrostFoundry"] = () => DadsQoLPlugin.EternalFrostFoundries.Value, ["eitrrefinery"] = () => DadsQoLPlugin.EternalEitrRefineries.Value }; internal static bool EnabledFor(Component component) { if ((Object)(object)component == (Object)null || !DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.EternalFuelEnabled)) { return false; } string value = PrefabNames.GetValue(component, delegate(Component current) { string name = ((Object)current.gameObject).name; return new CachedName { Value = (name.EndsWith("(Clone)", StringComparison.OrdinalIgnoreCase) ? name.Substring(0, name.Length - "(Clone)".Length) : name) }; }).Value; if (BuiltInPrefabs.TryGetValue(value, out Func<bool> value2)) { return value2(); } return CustomPrefabs().Contains(value); } internal static void Fill(ZNetView view, float maximumFuel) { if (!((Object)(object)view == (Object)null) && view.IsValid() && view.IsOwner() && view.GetZDO() != null) { ZDO zDO = view.GetZDO(); if (zDO.GetFloat(ZDOVars.s_fuel, 0f) != maximumFuel) { zDO.Set(ZDOVars.s_fuel, maximumFuel); } } } private static HashSet<string> CustomPrefabs() { string text = DadsQoLPlugin.EternalCustomPrefabs.Value ?? string.Empty; if (string.Equals(text, _customPrefabSource, StringComparison.Ordinal)) { return _customPrefabs; } _customPrefabSource = text; _customPrefabs = new HashSet<string>(from value in text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries) select value.Trim() into value where value.Length > 0 select value, StringComparer.OrdinalIgnoreCase); return _customPrefabs; } } [HarmonyPatch(typeof(Fireplace), "UpdateFireplace")] internal static class EternalFireplacePatch { private static void Prefix(Fireplace __instance, ZNetView ___m_nview, out bool __state) { __state = __instance.m_infiniteFuel; if (EternalFuel.EnabledFor((Component)(object)__instance)) { __instance.m_infiniteFuel = true; EternalFuel.Fill(___m_nview, __instance.m_maxFuel); } } private static void Postfix(Fireplace __instance, bool __state) { __instance.m_infiniteFuel = __state; } } [HarmonyPatch(typeof(CookingStation), "UpdateCooking")] internal static class EternalCookingStationUpdatePatch { private static void Prefix(CookingStation __instance, ZNetView ___m_nview) { if (EternalFuel.EnabledFor((Component)(object)__instance)) { EternalFuel.Fill(___m_nview, __instance.m_maxFuel); } } } [HarmonyPatch(typeof(CookingStation), "SetFuel")] internal static class EternalCookingStationSetFuelPatch { private static void Prefix(CookingStation __instance, ZNetView ___m_nview, ref float fuel) { if (EternalFuel.EnabledFor((Component)(object)__instance) && (Object)(object)___m_nview != (Object)null && ___m_nview.IsValid() && ___m_nview.IsOwner()) { fuel = __instance.m_maxFuel; } } } [HarmonyPatch(typeof(Smelter), "UpdateSmelter")] internal static class EternalSmelterUpdatePatch { private static void Prefix(Smelter __instance, ZNetView ___m_nview) { if (EternalFuel.EnabledFor((Component)(object)__instance)) { EternalFuel.Fill(___m_nview, __instance.m_maxFuel); } } } [HarmonyPatch(typeof(Smelter), "SetFuel")] internal static class EternalSmelterSetFuelPatch { private static void Prefix(Smelter __instance, ZNetView ___m_nview, ref float fuel) { if (EternalFuel.EnabledFor((Component)(object)__instance) && (Object)(object)___m_nview != (Object)null && ___m_nview.IsValid() && ___m_nview.IsOwner()) { fuel = __instance.m_maxFuel; } } } internal static class MultiplayerSharing { private const string HelloRpc = "DadsQoL_SharingHello"; private const string RecipeRpc = "DadsQoL_SharingRecipe"; private const string MapRpc = "DadsQoL_SharingMap"; private const string StateRpc = "DadsQoL_SharingState"; private const int MaximumMapBytes = 2097152; private static readonly FieldInfo KnownRecipesField = AccessTools.Field(typeof(Player), "m_knownRecipes"); private static readonly FieldInfo BuildPiecesField = AccessTools.Field(typeof(ObjectDB), "m_buildPieces"); private static readonly FieldInfo ExploredField = AccessTools.Field(typeof(Minimap), "m_explored"); private static readonly FieldInfo ExploredOthersField = AccessTools.Field(typeof(Minimap), "m_exploredOthers"); private static readonly FieldInfo FogTextureField = AccessTools.Field(typeof(Minimap), "m_fogTexture"); private static readonly MethodInfo AddKnownRecipeMethod = AccessTools.Method(typeof(Player), "AddKnownRecipe", (Type[])null, (Type[])null); private static readonly MethodInfo AddKnownPieceMethod = AccessTools.Method(typeof(Player), "AddKnownPiece", (Type[])null, (Type[])null); private static readonly HashSet<string> ServerRecipes = new HashSet<string>(StringComparer.Ordinal); private static byte[] _serverMap = Array.Empty<byte>(); private static ZRoutedRpc? _router; private static long _worldId; private static bool _helloSent; private static bool _mapDirty; private static bool _applyingRecipes; private static float _nextMapSend; private static string? _savePath; internal static Player? LoadedPlayer; internal static Minimap? LoadedMap; internal static void Reset() { _router = null; _worldId = 0L; _helloSent = false; _mapDirty = false; _savePath = null; ServerRecipes.Clear(); _serverMap = Array.Empty<byte>(); LoadedPlayer = null; LoadedMap = null; } internal static void Update() { //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Expected O, but got Unknown ZNet instance = ZNet.instance; ZRoutedRpc instance2 = ZRoutedRpc.instance; if ((Object)(object)instance == (Object)null || instance2 == null || instance.GetWorld() == null) { return; } long worldUID = instance.GetWorldUID(); if (_router != instance2 || _worldId != worldUID) { _router = instance2; _worldId = worldUID; _helloSent = false; _mapDirty = false; ServerRecipes.Clear(); _serverMap = Array.Empty<byte>(); _savePath = null; instance2.Register<ZPackage>("DadsQoL_SharingHello", (Action<long, ZPackage>)OnHello); instance2.Register<ZPackage>("DadsQoL_SharingRecipe", (Action<long, ZPackage>)OnRecipe); instance2.Register<ZPackage>("DadsQoL_SharingMap", (Action<long, ZPackage>)OnMap); instance2.Register<ZPackage>("DadsQoL_SharingState", (Action<long, ZPackage>)OnState); if (instance.IsServer() && worldUID != 0L) { LoadServerState(worldUID); } } Player localPlayer = Player.m_localPlayer; Minimap instance3 = Minimap.instance; if ((Object)(object)localPlayer == (Object)null || (Object)(object)instance3 == (Object)null || (Object)(object)LoadedPlayer != (Object)(object)localPlayer || (Object)(object)LoadedMap != (Object)(object)instance3 || worldUID == 0L) { return; } if (!_helloSent) { if (!instance.IsServer() && instance.GetServerPeer() == null) { return; } _helloSent = true; if (instance.IsServer()) { bool num = MergeLocal(localPlayer, instance3); ApplyState(localPlayer, instance3); if (num) { BroadcastState(0L); } } else { instance2.InvokeRoutedRPC(instance.GetServerPeer().m_uid, "DadsQoL_SharingHello", new object[1] { MakeHello(localPlayer, instance3) }); } _nextMapSend = Time.unscaledTime + 10f; } if (!DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.AutomaticMapSharing) || (!_mapDirty && !(Time.unscaledTime >= _nextMapSend + 110f)) || !(Time.unscaledTime >= _nextMapSend)) { return; } _mapDirty = false; _nextMapSend = Time.unscaledTime + 10f; byte[] mapBits = GetMapBits(instance3); if (instance.IsServer()) { if (MergeMap(mapBits)) { BroadcastState(0L); } return; } ZPackage val = new ZPackage(); val.Write(Compress(mapBits)); ZNetPeer serverPeer = instance.GetServerPeer(); if (serverPeer != null) { instance2.InvokeRoutedRPC(serverPeer.m_uid, "DadsQoL_SharingMap", new object[1] { val }); } } internal static void RecipeDiscovered(Player player, Recipe recipe) { string name = recipe?.m_item?.m_itemData?.m_shared?.m_name ?? string.Empty; KnownDiscovered(player, name); } internal static void PieceDiscovered(Player player, Piece piece) { KnownDiscovered(player, piece?.m_name ?? string.Empty); } private static void KnownDiscovered(Player player, string name) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown if (_applyingRecipes || !_helloSent || (Object)(object)player != (Object)(object)Player.m_localPlayer || !DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.SharedRecipes) || string.IsNullOrEmpty(name)) { return; } ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || _router == null) { return; } if (instance.IsServer()) { if (ServerRecipes.Add(name)) { SaveServerState(); BroadcastState(0L); } return; } ZPackage val = new ZPackage(); val.Write(name); ZNetPeer serverPeer = instance.GetServerPeer(); if (serverPeer != null) { _router.InvokeRoutedRPC(serverPeer.m_uid, "DadsQoL_SharingRecipe", new object[1] { val }); } } internal static void MapExplored(Minimap map) { if ((Object)(object)map == (Object)(object)Minimap.instance) { _mapDirty = true; } } private static ZPackage MakeHello(Player player, Minimap map) { //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(); bool flag = DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.SharedRecipes); bool flag2 = DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.AutomaticMapSharing); val.Write(flag); val.Write(flag2); HashSet<string> hashSet = (flag ? GetKnownRecipes(player) : new HashSet<string>()); val.Write(hashSet.Count); foreach (string item in hashSet) { val.Write(item); } val.Write(flag2 ? Compress(GetMapBits(map)) : Array.Empty<byte>()); return val; } private static void OnHello(long sender, ZPackage package) { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer() || instance.GetPeer(sender) == null) { return; } bool flag = package.ReadBool(); bool flag2 = package.ReadBool(); int num = package.ReadInt(); if (num < 0 || num > 10000) { return; } bool flag3 = false; for (int i = 0; i < num; i++) { string text = package.ReadString(); if (flag && DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.SharedRecipes)) { int length = text.Length; if (length > 0 && length < 256) { flag3 |= ServerRecipes.Add(text); } } } byte[] bytes = package.ReadByteArray(); if (flag2 && DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.AutomaticMapSharing)) { flag3 |= MergeMap(Decompress(bytes)); } if (flag3) { SaveServerState(); } SendState(sender); if (flag3) { BroadcastState(sender); } } private static void OnRecipe(long sender, ZPackage package) { ZNet instance = ZNet.instance; if (!((Object)(object)instance == (Object)null) && instance.IsServer() && instance.GetPeer(sender) != null && DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.SharedRecipes)) { string text = package.ReadString(); int length = text.Length; if (length > 0 && length < 256 && ServerRecipes.Add(text)) { SaveServerState(); BroadcastState(0L); } } } private static void OnMap(long sender, ZPackage package) { ZNet instance = ZNet.instance; if (!((Object)(object)instance == (Object)null) && instance.IsServer() && instance.GetPeer(sender) != null && DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.AutomaticMapSharing) && MergeMap(Decompress(package.ReadByteArray()))) { SaveServerState(); BroadcastState(0L); } } private static void OnState(long sender, ZPackage package) { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || instance.IsServer() || instance.GetServerPeer() == null || sender != instance.GetServerPeer().m_uid) { return; } Player localPlayer = Player.m_localPlayer; Minimap instance2 = Minimap.instance; if ((Object)(object)localPlayer == (Object)null || (Object)(object)instance2 == (Object)null || (Object)(object)LoadedPlayer != (Object)(object)localPlayer || (Object)(object)LoadedMap != (Object)(object)instance2) { return; } int num = package.ReadInt(); if (num >= 0 && num <= 10000) { HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); for (int i = 0; i < num; i++) { hashSet.Add(package.ReadString()); } byte[] bits = Decompress(package.ReadByteArray()); if (DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.SharedRecipes)) { ApplyRecipes(localPlayer, hashSet); } if (DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.AutomaticMapSharing)) { ApplyMap(instance2, bits); } } } private static bool MergeLocal(Player player, Minimap map) { bool flag = false; if (DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.SharedRecipes)) { foreach (string knownRecipe in GetKnownRecipes(player)) { flag |= ServerRecipes.Add(knownRecipe); } } if (DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.AutomaticMapSharing)) { flag |= MergeMap(GetMapBits(map)); } if (flag) { SaveServerState(); } return flag; } private static void ApplyState(Player player, Minimap map) { if (DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.SharedRecipes)) { ApplyRecipes(player, ServerRecipes); } if (DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.AutomaticMapSharing)) { ApplyMap(map, _serverMap); } } private static void ApplyRecipes(Player player, IEnumerable<string> names) { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { return; } _applyingRecipes = true; try { foreach (string name in names) { if (player.IsRecipeKnown(name)) { continue; } foreach (Recipe recipe in instance.m_recipes) { if (recipe?.m_item?.m_itemData?.m_shared?.m_name != name) { continue; } AddKnownRecipeMethod.Invoke(player, new object[1] { recipe }); goto IL_0125; } foreach (Piece item in (List<Piece>)BuildPiecesField.GetValue(instance)) { if (!(item?.m_name != name)) { AddKnownPieceMethod.Invoke(player, new object[1] { item }); break; } } IL_0125:; } } finally { _applyingRecipes = false; } } private static HashSet<string> GetKnownRecipes(Player player) { return (HashSet<string>)KnownRecipesField.GetValue(player); } private static byte[] GetMapBits(Minimap map) { BitArray obj = (BitArray)ExploredField.GetValue(map); BitArray bitArray = (BitArray)ExploredOthersField.GetValue(map); byte[] array = new byte[(obj.Length + 7) / 8]; obj.CopyTo(array, 0); byte[] array2 = new byte[array.Length]; bitArray.CopyTo(array2, 0); for (int i = 0; i < array.Length; i++) { array[i] |= array2[i]; } return array; } private static bool MergeMap(byte[] incoming) { if (incoming.Length == 0 || incoming.Length > 2097152 || (_serverMap.Length != 0 && _serverMap.Length != incoming.Length)) { return false; } if (_serverMap.Length == 0) { _serverMap = new byte[incoming.Length]; } bool result = false; for (int i = 0; i < incoming.Length; i++) { byte b = (byte)(_serverMap[i] | incoming[i]); if (b != _serverMap[i]) { _serverMap[i] = b; result = true; } } return result; } private static void ApplyMap(Minimap map, byte[] bits) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown BitArray bitArray = (BitArray)ExploredField.GetValue(map); BitArray bitArray2 = (BitArray)ExploredOthersField.GetValue(map); if (bits.Length != (bitArray.Length + 7) / 8) { return; } Texture2D val = (Texture2D)FogTextureField.GetValue(map); Color[] array = null; bool flag = false; for (int i = 0; i < bitArray.Length; i++) { if ((bits[i >> 3] & (1 << (i & 7))) != 0 && !bitArray[i] && !bitArray2[i]) { if (array == null) { array = val.GetPixels(); } bitArray2[i] = true; array[i].g = 0f; flag = true; } } if (flag) { val.SetPixels(array); val.Apply(); } } private static void SendState(long peerId) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown if (_router == null) { return; } ZPackage val = new ZPackage(); bool flag = DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.SharedRecipes); val.Write(flag ? ServerRecipes.Count : 0); if (flag) { foreach (string serverRecipe in ServerRecipes) { val.Write(serverRecipe); } } val.Write(DadsQoLPlugin.FeatureEnabled(DadsQoLPlugin.AutomaticMapSharing) ? Compress(_serverMap) : Array.Empty<byte>()); _router.InvokeRoutedRPC(peerId, "DadsQoL_SharingState", new object[1] { val }); } private static void BroadcastState(long except = 0L) { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer()) { return; } foreach (ZNetPeer peer in instance.GetPeers()) { if (peer.IsReady() && peer.m_uid != except) { SendState(peer.m_uid); } } if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)Minimap.instance != (Object)null) { ApplyState(Player.m_localPlayer, Minimap.instance); } } private static byte[] Compress(byte[] bytes) { if (bytes.Length == 0) { return bytes; } using MemoryStream memoryStream = new MemoryStream(); using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, leaveOpen: true)) { gZipStream.Write(bytes, 0, bytes.Length); } return memoryStream.ToArray(); } private static byte[] Decompress(byte[] bytes) { if (bytes.Length == 0) { return bytes; } using MemoryStream stream = new MemoryStream(bytes); using GZipStream gZipStream = new GZipStream(stream, CompressionMode.Decompress); using MemoryStream memoryStream = new MemoryStream(); byte[] array = new byte[8192]; int num; while ((num = gZipStream.Read(array, 0, array.Length)) > 0) { if (memoryStream.Length + num > 2097152) { return Array.Empty<byte>(); } memoryStream.Write(array, 0, num); } return memoryStream.ToArray(); } private static void LoadServerState(long worldId) { _savePath = Path.Combine(Paths.ConfigPath, "DadsQoL", "multiplayer-" + worldId + ".dat"); if (!File.Exists(_savePath)) { return; } try { ReadState(File.ReadAllBytes(_savePath)); } catch (Exception ex) { DadsQoLPlugin.ModLog.LogWarning((object)("Could not read multiplayer state: " + ex.Message)); } } private static void SaveServerState() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown if (_savePath == null) { return; } try { if (File.Exists(_savePath) && !ReadState(File.ReadAllBytes(_savePath))) { return; } ZPackage val = new ZPackage(); val.Write(1); val.Write(ServerRecipes.Count); foreach (string serverRecipe in ServerRecipes) { val.Write(serverRecipe); } val.Write(_serverMap); Directory.CreateDirectory(Path.GetDirectoryName(_savePath)); File.WriteAllBytes(_savePath, val.GetArray()); } catch (Exception ex) { DadsQoLPlugin.ModLog.LogWarning((object)("Could not save multiplayer state: " + ex.Message)); } } private static bool ReadState(byte[] bytes) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ZPackage val = new ZPackage(bytes); if (val.ReadInt() != 1) { return false; } int num = val.ReadInt(); if (num < 0 || num > 10000) { return false; } for (int i = 0; i < num; i++) { ServerRecipes.Add(val.ReadString()); } byte[] array = val.ReadByteArray(); if (array.Length != 0 && _serverMap.Length != 0 && array.Length != _serverMap.Length) { return false; } MergeMap(array); return true; } } [HarmonyPatch(typeof(Player), "AddKnownRecipe")] internal static class SharedRecipePatch { private static void Postfix(Player __instance, Recipe recipe) { MultiplayerSharing.RecipeDiscovered(__instance, recipe); } } [HarmonyPatch(typeof(Player), "AddKnownPiece")] internal static class SharedPiecePatch { private static void Postfix(Player __instance, Piece piece) { MultiplayerSharing.PieceDiscovered(__instance, piece); } } [HarmonyPatch(typeof(Player), "Load", new Type[] { typeof(ZPackage) })] internal static class SharedRecipeLoadPatch { private static void Postfix(Player __instance) { MultiplayerSharing.LoadedPlayer = __instance; } } [HarmonyPatch(typeof(Minimap), "LoadMapData")] internal static class SharedMapLoadPatch { private static void Postfix(Minimap __instance) { MultiplayerSharing.LoadedMap = __instance; } } [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(int), typeof(int) })] internal static class SharedMapExplorePatch { private static void Postfix(Minimap __instance, bool __result) { if (__result) { MultiplayerSharing.MapExplored(__instance); } } } } namespace DadsQoL.MassFarming { [HarmonyPatch(typeof(Player), "Interact")] internal static class MassHarvest { private static readonly FieldInfo InteractMaskField = AccessTools.Field(typeof(Player), "m_interactMask"); private static readonly MethodInfo ExtractMethod = AccessTools.Method(typeof(Beehive), "Extract", Type.EmptyTypes, (Type[])null); private static bool _processingMassInteraction; private static Collider[] _colliders = (Collider[])(object)new Collider[64]; private static void Prefix(Player __instance, GameObject go, bool hold, bool alt) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) if (!DadsQoLPlugin.MassFarmingActive || _processingMassInteraction || hold || ((Character)__instance).InAttack() || ((Character)__instance).InDodge() || !DadsQoLPlugin.MassFarmingShortcutHeld()) { return; } Interactable componentInParent = go.GetComponentInParent<Interactable>(); float num = Mathf.Max(0f, DadsQoLPlugin.MassHarvestRadius.Value); int num2 = (int)InteractMaskField.GetValue(__instance); int num3; while (true) { num3 = Physics.OverlapSphereNonAlloc(go.transform.position, num, _colliders, num2); if (num3 < _colliders.Length) { break; } Array.Resize(ref _colliders, _colliders.Length * 2); } _processingMassInteraction = true; try { Pickable val = (Pickable)(object)((componentInParent is Pickable) ? componentInParent : null); if (val != null) { string text = (((Object)(object)val.m_itemPrefab != (Object)null) ? ((Object)val.m_itemPrefab).name : string.Empty); for (int i = 0; i < num3; i++) { Collider val2 = _colliders[i]; Pickable val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject.GetComponentInParent<Pickable>() : null); if ((Object)(object)val3 != (Object)null && (Object)(object)val3 != (Object)(object)val && (Object)(object)val3.m_itemPrefab != (Object)null && ((Object)val3.m_itemPrefab).name == text) { val3.Interact((Humanoid)(object)__instance, false, alt); } } return; } Beehive val4 = (Beehive)(object)((componentInParent is Beehive) ? componentInParent : null); if (val4 == null) { return; } for (int j = 0; j < num3; j++) { Collider val5 = _colliders[j]; Beehive val6 = (((Object)(object)val5 != (Object)null) ? ((Component)val5).gameObject.GetComponentInParent<Beehive>() : null); if ((Object)(object)val6 != (Object)null && (Object)(object)val6 != (Object)(object)val4 && PrivateArea.CheckAccess(((Component)val6).transform.position, 0f, true, false)) { ExtractMethod.Invoke(val6, null); } } } finally { Array.Clear(_colliders, 0, num3); _processingMassInteraction = false; } } } internal static class MassPlantingState { private static readonly FieldInfo NoPlacementCostField = AccessTools.Field(typeof(Player), "m_noPlacementCost"); private static readonly FieldInfo PlacementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost"); private static readonly FieldInfo BuildPiecesField = AccessTools.Field(typeof(Player), "m_buildPieces"); private static readonly MethodInfo GetRightItemMethod = AccessTools.Method(typeof(Humanoid), "GetRightItem", (Type[])null, (Type[])null); internal static Vector3 PlacedPosition; internal static Quaternion PlacedRotation; internal static Piece PlacedPiece = null; internal static bool PlaceSuccessful; internal static int? SavedRotation; internal static GameObject[] PlacementGhosts = (GameObject[])(object)new GameObject[1]; internal static Piece[] PlacementGhostPieces = (Piece[])(object)new Piece[1]; private static readonly List<Material> GhostMaterials = new List<Material>(); internal static Piece FakeResourcePiece = null; internal static readonly int PlantSpaceMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" }); internal static bool Active { get { if (DadsQoLPlugin.MassFarmingActive) { return DadsQoLPlugin.MassFarmingShortcutHeld(); } return false; } } internal static bool NoPlacementCost(Player player) { return (bool)NoPlacementCostField.GetValue(player); } internal static GameObject? PlacementGhost(Player player) { object? value = PlacementGhostField.GetValue(player); return (GameObject?)((value is GameObject) ? value : null); } internal static PieceTable? BuildPieces(Player player) { object? value = BuildPiecesField.GetValue(player); return (PieceTable?)((value is PieceTable) ? value : null); } internal static ItemData? RightItem(Player player) { object? obj = GetRightItemMethod.Invoke(player, Array.Empty<object>()); return (ItemData?)((obj is ItemData) ? obj : null); } internal static IEnumerable<Vector3> BuildGridPositions(Vector3 origin, Plant plant, Quaternion rotation) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) int width = Math.Max(1, DadsQoLPlugin.PlantGridWidth.Value); int length = Math.Max(1, DadsQoLPlugin.PlantGridLength.Value); float num = plant.m_growRadius * 2f; Vector3 across = rotation * Vector3.left * num; Vector3 forward = rotation * Vector3.forward * num; Vector3 gridOrigin = origin; if (DadsQoLPlugin.CenterPlantingGridLength.Value) { gridOrigin -= forward * (float)(length / 2); } if (DadsQoLPlugin.CenterPlantingGridWidth.Value) { gridOrigin -= across * (float)(width / 2); } for (int x = 0; x < length; x++) { Vector3 position = gridOrigin; for (int z = 0; z < width; z++) { position.y = ZoneSystem.instance.GetGroundHeight(position); yield return position; position += across; } gridOrigin += forward; } } internal static bool HasGrowSpace(Vector3 position, GameObject prefab) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) Plant component = prefab.GetComponent<Plant>(); if (!((Object)(object)component == (Object)null)) { return !Physics.CheckSphere(position, component.m_growRadius, PlantSpaceMask); } return true; } internal static bool EnsureGhostsBuilt(Player player) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected O, but got Unknown int num = Math.Max(1, DadsQoLPlugin.PlantGridWidth.Value) * Math.Max(1, DadsQoLPlugin.PlantGridLength.Value); if (PlacementGhosts.Length != num || (Object)(object)PlacementGhosts[0] == (Object)null) { DestroyGhosts(); PlacementGhosts = (GameObject[])(object)new GameObject[num]; PlacementGhostPieces = (Piece[])(object)new Piece[num]; PieceTable val = BuildPieces(player); GameObject val2 = (((Object)(object)val != (Object)null) ? val.GetSelectedPrefab() : null); if ((Object)(object)val2 == (Object)null || val2.GetComponent<Piece>().m_repairPiece) { return false; } for (int i = 0; i < PlacementGhosts.Length; i++) { PlacementGhosts[i] = CreateGhost(val2); PlacementGhostPieces[i] = PlacementGhosts[i].GetComponent<Piece>(); } } if ((Object)(object)FakeResourcePiece == (Object)null) { FakeResourcePiece = PlacementGhostPieces[0]; FakeResourcePiece.m_dlc = string.Empty; FakeResourcePiece.m_resources = (Requirement[])(object)new Requirement[1] { new Requirement() }; } return true; } internal static void DestroyGhosts() { GameObject[] placementGhosts = PlacementGhosts; foreach (GameObject val in placementGhosts) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } foreach (Material ghostMaterial in GhostMaterials) { if ((Object)(object)ghostMaterial != (Object)null) { Object.Destroy((Object)(object)ghostMaterial); } } GhostMaterials.Clear(); FakeResourcePiece = null; PlacementGhostPieces = (Piece[])(object)new Piece[1]; } internal static void SetGhostsActive(bool active) { GameObject[] placementGhosts = PlacementGhosts; foreach (GameObject val in placementGhosts) { if ((Object)(object)val != (Object)null) { val.SetActive(active); } } } private static GameObject CreateGhost(GameObject prefab) { //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown ZNetView.m_forceDisableInit = true; GameObject val; try { val = Object.Instantiate<GameObject>(prefab); } finally { ZNetView.m_forceDisableInit = false; } ((Object)val).name = ((Object)prefab).name; Joint[] componentsInChildren = val.GetComponentsInChildren<Joint>(); for (int i = 0; i < componentsInChildren.Length; i++) { Object.Destroy((Object)(object)componentsInChildren[i]); } Rigidbody[] componentsInChildren2 = val.GetComponentsInChildren<Rigidbody>(); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.Destroy((Object)(object)componentsInChildren2[i]); } int layer = LayerMask.NameToLayer("ghost"); Transform[] componentsInChildren3 = val.GetComponentsInChildren<Transform>(); for (int i = 0; i < componentsInChildren3.Length; i++) { ((Component)componentsInChildren3[i]).gameObject.layer = layer; } TerrainModifier[] componentsInChildren4 = val.GetComponentsInChildren<TerrainModifier>(); for (int i = 0; i < componentsInChildren4.Length; i++) { Object.Destroy((Object)(object)componentsInChildren4[i]); } GuidePoint[] componentsInChildren5 = val.GetComponentsInChildren<GuidePoint>(); for (int i = 0; i < componentsInChildren5.Length; i++) { Object.Destroy((Object)(object)componentsInChildren5[i]); } Light[] componentsInChildren6 = val.GetComponentsInChildren<Light>(); for (int i = 0; i < componentsInChildren6.Length; i++) { Object.Destroy((Object)(object)componentsInChildren6[i]); } Transform val2 = val.transform.Find("_GhostOnly"); if ((Object)(object)val2 != (Object)null) { ((Component)val2).gameObject.SetActive(true); } MeshRenderer[] componentsInChildren7 = val.GetComponentsInChildren<MeshRenderer>(); foreach (MeshRenderer val3 in componentsInChildren7) { if (!((Object)(object)((Renderer)val3).sharedMaterial == (Object)null)) { Material[] sharedMaterials = ((Renderer)val3).sharedMaterials; for (int j = 0; j < sharedMaterials.Length; j++) { Material val4 = new Material(sharedMaterials[j]); val4.SetFloat("_RippleDistance", 0f); val4.SetFloat("_ValueNoise", 0f); sharedMaterials[j] = val4; GhostMaterials.Add(val4); } ((Renderer)val3).sharedMaterials = sharedMaterials; ((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0; } } return val; } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class TryPlacePiecePatch { private static void Prefix(int ___m_placeRotation) { if (MassPlantingState.Active && !MassPlantingState.SavedRotation.HasValue) { MassPlantingState.SavedRotation = ___m_placeRotation; } } private static void Postfix(Player __instance, bool __result, Piece piece, ref int ___m_placeRotation) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) MassPlantingState.PlaceSuccessful = __result; GameObject val = MassPlantingState.PlacementGhost(__instance); if (__result && (Object)(object)val != (Object)null) { MassPlantingState.PlacedPosition = val.transform.position; MassPlantingState.PlacedRotation = val.transform.rotation; MassPlantingState.PlacedPiece = piece; } if (MassPlantingState.Active && MassPlantingState.SavedRotation.HasValue) { ___m_placeRotation = MassPlantingState.SavedRotation.Value; } } } [HarmonyPatch(typeof(Player), "UpdatePlacement")] internal static class UpdatePlacementPatch { private static void Prefix(ref int ___m_placeRotation) { MassPlantingState.PlaceSuccessful = false; if (MassPlantingState.Active && MassPlantingState.SavedRotation.HasValue) { ___m_placeRotation = MassPlantingState.SavedRotation.Value; } } private static void Postfix(Player __instance, int ___m_placeRotation) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) if (MassPlantingState.Active) { MassPlantingState.SavedRotation = ___m_placeRotation; } if (!MassPlantingState.PlaceSuccessful || !MassPlantingState.Active) { return; } Plant component = ((Component)MassPlantingState.PlacedPiece).gameObject.GetComponent<Plant>(); Heightmap val = Heightmap.FindHeightmap(MassPlantingState.PlacedPosition); if ((Object)(object)component == (Object)null || (Object)(object)val == (Object)null) { return; } PieceTable val2 = MassPlantingState.BuildPieces(__instance); foreach (Vector3 item in MassPlantingState.BuildGridPositions(MassPlantingState.PlacedPosition, component, MassPlantingState.PlacedRotation)) { if (MassPlantingState.PlacedPosition == item || (MassPlantingState.PlacedPiece.m_cultivatedGroundOnly && !val.IsCultivated(item)) || !MassPlantingState.HasGrowSpace(item, ((Component)MassPlantingState.PlacedPiece).gameObject)) { continue; } ItemData val3 = MassPlantingState.RightItem(__instance); if (val3 == null) { break; } if (!DadsQoLPlugin.IgnorePlantingStamina.Value && !((Character)__instance).HaveStamina(val3.m_shared.m_attack.m_attackStamina)) { Hud.instance.StaminaBarUppgradeFlash(); break; } if (!MassPlantingState.NoPlacementCost(__instance) && !__instance.HaveRequirements(MassPlantingState.PlacedPiece, (RequirementMode)0)) { break; } GameObject val4 = Object.Instantiate<GameObject>(((Component)MassPlantingState.PlacedPiece).gameObject, item, MassPlantingState.PlacedRotation); Piece component2 = val4.GetComponent<Piece>(); if ((Object)(object)component2 != (Object)null) { component2.SetCreator(__instance.GetPlayerID(), ((IUser)PlatformManager.DistributionPlatform.LocalUser).PlatformUserID); } MassPlantingState.PlacedPiece.m_placeEffect.Create(item, MassPlantingState.PlacedRotation, val4.transform, 1f, -1, default(ZDOID)); Game.instance.IncrementPlayerStat((PlayerStatType)2, 1f, false); __instance.ConsumeResources(MassPlantingState.PlacedPiece.m_resources, 0, -1, 1); if (!DadsQoLPlugin.IgnorePlantingStamina.Value) { ((Character)__instance).UseStamina(val3.m_shared.m_attack.m_attackStamina); } if ((Object)(object)val2 != (Object)null) { ((Character)__instance).RaiseSkill(val2.m_skill, 1f); } if (!DadsQoLPlugin.IgnorePlantingDurability.Value && val3.m_shared.m_useDurability) { val3.m_durability -= val3.m_shared.m_useDurabilityDrain; if (val3.m_durability <= 0f) { break; } } } } } [HarmonyPatch(typeof(Player), "SetupPlacementGhost")] internal static class SetupPlacementGhostPatch { private static void Prefix(int ___m_placeRotation) { if (MassPlantingState.Active && !MassPlantingState.SavedRotation.HasValue) { MassPlantingState.SavedRotation = ___m_placeRotation; } } private static void Postfix(ref int ___m_placeRotation) { if (MassPlantingState.Active && MassPlantingState.SavedRotation.HasValue) { ___m_placeRotation = MassPlantingState.SavedRotation.Value; } MassPlantingState.DestroyGhosts(); } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] internal static class UpdatePlacementGhostPatch { private static void Postfix(Player __instance) { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: 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_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) GameObject val = MassPlantingState.PlacementGhost(__instance); if (!DadsQoLPlugin.MassFarmingActive || !DadsQoLPlugin.MassFarmingShortcutHeld() || (Object)(object)val == (Object)null || !val.activeSelf) { MassPlantingState.SetGhostsActive(active: false); return; } Plant component = val.GetComponent<Plant>(); if ((Object)(object)component == (Object)null || !MassPlantingState.EnsureGhostsBuilt(__instance)) { MassPlantingState.SetGhostsActive(active: false); return; } Piece component2 = val.GetComponent<Piece>(); Requirement val2 = ((IEnumerable<Requirement>)component2.m_resources).FirstOrDefault((Func<Requirement, bool>)((Requirement resource) => (Object)(object)resource.m_resItem != (Object)null && resource.m_amount > 0)); if (val2 == null) { MassPlantingState.SetGhostsActive(active: false); return; } MassPlantingState.FakeResourcePiece.m_resources[0].m_resItem = val2.m_resItem; MassPlantingState.FakeResourcePiece.m_resources[0].m_amount = 0; ItemData val3 = MassPlantingState.RightItem(__instance); Heightmap val4 = Heightmap.FindHeightmap(val.transform.position); if (val3 == null || (Object)(object)val4 == (Object)null) { MassPlantingState.SetGhostsActive(active: false); return; } float num = __instance.GetStamina(); bool flag = MassPlantingState.NoPlacementCost(__instance); Vector3 position = val.transform.position; Quaternion rotation = val.transform.rotation; int num2 = 0; foreach (Vector3 item in MassPlantingState.BuildGridPositions(position, component, rotation)) { GameObject val5 = MassPlantingState.PlacementGhosts[num2]; Piece val6 = MassPlantingState.PlacementGhostPieces[num2++]; if (position == item) { if (val5.activeSelf) { val5.SetActive(false); } continue; } Requirement obj = MassPlantingState.FakeResourcePiece.m_resources[0]; obj.m_amount += val2.m_amount; val5.transform.position = item; val5.transform.rotation = rotation; if (!val5.activeSelf) { val5.SetActive(true); } bool invalidPlacementHeightlight = (component2.m_cultivatedGroundOnly && !val4.IsCultivated(item)) || !MassPlantingState.HasGrowSpace(item, val) || (!DadsQoLPlugin.IgnorePlantingStamina.Value && num < val3.m_shared.m_attack.m_attackStamina) || (!flag && !__instance.HaveRequirements(MassPlantingState.FakeResourcePiece, (RequirementMode)0)); num -= val3.m_shared.m_attack.m_attackStamina; val6.SetInvalidPlacementHeightlight(invalidPlacementHeightlight); } } } }