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 MarsarahTweaks v1.8.3
MarsarahTweaks.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using JetBrains.Annotations; using MarsarahTweaks.Managers; using MarsarahTweaks.Patches.Balance; using MarsarahTweaks.Patches.Features; using MarsarahTweaks.Patches.Grind; using MarsarahTweaks.Patches.QOL; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("MarsarahTweaks")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("MarsarahTweaks")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("831fc141-e3fa-4e67-9d2f-5e56cf6f3935")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace MarsarahTweaks { [BepInPlugin("Marsarah.MarsarahTweaks", "MarsarahTweaks", "1.8.3")] public class MarsarahTweaks : BaseUnityPlugin { internal const string ModName = "MarsarahTweaks"; internal const string ModVersion = "1.8.3"; internal const string Author = "Marsarah"; public const string ModGUID = "Marsarah.MarsarahTweaks"; private readonly Harmony harmony = new Harmony("Marsarah.MarsarahTweaks"); private void Awake() { LogManager.SetGlobalLogLevel(LogManager.LogLevel.Warning); ConfigManager.Init(((BaseUnityPlugin)this).Config); harmony.PatchAll(); } private void Start() { CompatibilityManager.Initialize(); CompatibilityManager.UpdateIncompatibilities(); } private void OnDestroy() { ((BaseUnityPlugin)this).Config.Save(); } } } namespace MarsarahTweaks.Patches { public static class GlobalKeyChecker { [HarmonyPatch(typeof(ZoneSystem), "Update")] private class BossStatusUpdate_Patch { private static void Postfix(ZoneSystem __instance) { UpdateDefeatedStates(__instance); EikthyrDefeated = CheckGlobalKey("defeated_eikthyr"); ElderDefeated = CheckGlobalKey("defeated_gdking"); BonemassDefeated = CheckGlobalKey("defeated_bonemass"); ModerDefeated = CheckGlobalKey("defeated_dragon"); YagluthDefeated = CheckGlobalKey("defeated_goblinking"); QueenDefeated = CheckGlobalKey("defeated_queen"); FaderDefeated = CheckGlobalKey("defeated_fader"); BrennaDefeated = CheckGlobalKey("hildir1"); GeirrhafaDefeated = CheckGlobalKey("hildir2"); ThungrNZilDefeated = CheckGlobalKey("hildir3"); } } private static readonly LogManager log = new LogManager("Global Key Checker", LogManager.LogLevel.Warning); public static bool EikthyrDefeated = false; public static bool ElderDefeated = false; public static bool BonemassDefeated = false; public static bool ModerDefeated = false; public static bool YagluthDefeated = false; public static bool QueenDefeated = false; public static bool FaderDefeated = false; public static bool BrennaDefeated = false; public static bool GeirrhafaDefeated = false; public static bool ThungrNZilDefeated = false; private static string lastGlobalKeysSnapshot = null; private static readonly Dictionary<string, bool> globalKeyStates = new Dictionary<string, bool> { { "defeated_eikthyr", false }, { "defeated_gdking", false }, { "defeated_bonemass", false }, { "defeated_dragon", false }, { "defeated_goblinking", false }, { "defeated_queen", false }, { "defeated_fader", false }, { "hildir1", false }, { "hildir2", false }, { "hildir3", false } }; private static readonly Dictionary<string, string> bossToGlobalKey = new Dictionary<string, string> { { "Eikthyr", "defeated_eikthyr" }, { "The Elder", "defeated_gdking" }, { "Bonemass", "defeated_bonemass" }, { "Moder", "defeated_dragon" }, { "Yagluth", "defeated_goblinking" }, { "The Queen", "defeated_queen" }, { "Fader", "defeated_fader" }, { "Brenna", "hildir1" }, { "Geirrhafa", "hildir2" }, { "ThungrNZil", "hildir3" } }; private static void UpdateDefeatedStates(ZoneSystem zoneSystem) { List<string> globalKeys = zoneSystem.GetGlobalKeys(); string text = string.Join(", ", globalKeys.OrderBy((string key) => key)); bool flag = text != lastGlobalKeysSnapshot; if (flag) { log.Info($"=== Global Keys ({globalKeys.Count}) ==="); log.Info((globalKeys.Count > 0) ? text : "(none)"); } foreach (string item in globalKeyStates.Keys.ToList()) { bool flag2 = globalKeys.Contains(item); if (globalKeyStates[item] != flag2) { log.Info($"Key state changed: {item} | {globalKeyStates[item]} -> {flag2}"); globalKeyStates[item] = flag2; } } if (!flag) { return; } log.Info("=== Expected Key States ==="); foreach (KeyValuePair<string, bool> globalKeyState in globalKeyStates) { log.Info($"{globalKeyState.Key}: {globalKeyState.Value}"); } log.Info("=== End Global Keys ==="); lastGlobalKeysSnapshot = text; } private static bool CheckGlobalKey(string globalKey) { return globalKeyStates.ContainsKey(globalKey) && globalKeyStates[globalKey]; } public static bool IsBossDefeated(string boss) { if (bossToGlobalKey.TryGetValue(boss, out var value)) { return CheckGlobalKey(value); } log.Warn("IsBossDefeated called with unknown boss: " + boss); return false; } } } namespace MarsarahTweaks.Patches.QOL { internal static class HoeRadiusChanges { [HarmonyPatch(typeof(Player), "UpdatePlacement")] private static class Player_UpdatePlacement_Patch { private static void Prefix(Player __instance, bool takeInput, PieceTable ___m_buildPieces, GameObject ___m_placementGhost) { interceptPlacementScroll = false; if (!ConfigManager.AdjustableHoeRadiusEnabled.Value || !TryGetSupportedOperation(__instance, ___m_buildPieces, out var operation)) { RestoreOriginalSettings(); return; } if ((Object)(object)activeOperation != (Object)(object)operation) { SelectOperation(operation); } if ((Object)(object)activeOperation == (Object)null) { return; } UpdatePreview(___m_placementGhost); if (!takeInput || Hud.IsPieceSelectionVisible()) { return; } float mouseScrollWheel = ZInput.GetMouseScrollWheel(); if (!(Mathf.Abs(mouseScrollWheel) < 0.001f)) { interceptPlacementScroll = true; float num = Mathf.Clamp(currentRadius + Mathf.Sign(mouseScrollWheel) * 1f, GetMinimumRadius(activeOperation), 7f); if (!Mathf.Approximately(num, currentRadius)) { currentRadius = num; savedRadii[((Object)((Component)activeOperation).gameObject).name] = currentRadius; ApplyRadius(activeOperation.m_settings, currentRadius / defaultRadius); UpdatePreview(___m_placementGhost); log.Info($"Adjusted '{((Object)activeOperation).name}' radius to {currentRadius:0.##}m."); } } } private static void Postfix() { interceptPlacementScroll = false; } private static Exception Finalizer(Exception __exception) { interceptPlacementScroll = false; return __exception; } } [HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")] private static class ZInput_GetMouseScrollWheel_Patch { private static void Postfix(ref float __result) { if (interceptPlacementScroll || suppressCameraZoom) { __result = 0f; } } } [HarmonyPatch(typeof(Player), "Update")] private static class Player_Update_Patch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && (!ConfigManager.AdjustableHoeRadiusEnabled.Value || !((Character)__instance).InPlaceMode())) { RestoreOriginalSettings(); } } } [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] private static class GameCamera_UpdateCamera_Patch { private static void Prefix() { suppressCameraZoom = false; Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && ConfigManager.AdjustableHoeRadiusEnabled.Value && ((Character)localPlayer).InPlaceMode() && !Hud.IsPieceSelectionVisible()) { suppressCameraZoom = TryGetSupportedOperation(localPlayer, buildPiecesRef.Invoke(localPlayer), out var _); } } private static Exception Finalizer(Exception __exception) { suppressCameraZoom = false; return __exception; } } [HarmonyPatch(typeof(Settings), "Serialize")] private static class TerrainSettings_Serialize_Patch { private static void Postfix(ZPackage __0, GameObject __1) { if (!ConfigManager.AdjustableHoeRadiusEnabled.Value || (Object)(object)activeOperation == (Object)null || __0 == null || (Object)(object)__1 == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } string text = ((Object)__1).name; if (text.EndsWith("(Clone)", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "(Clone)".Length); } if (!(text != ((Object)activeOperation).name)) { int stableHashCode = StringExtensionMethods.GetStableHashCode(text); if (SupportedTerrainHashes.Contains(stableHashCode)) { __0.Write(1297371720); __0.Write(1); __0.Write(stableHashCode); __0.Write(currentRadius); log.Info($"Sent terrain radius: Piece={text}, Radius={currentRadius:0.##}m, Hash={stableHashCode}."); } } } } [HarmonyPatch(typeof(Settings), "Deserialize")] private static class TerrainSettings_Deserialize_Patch { private static void Postfix(ZPackage __0, ref Settings __result) { if (!ConfigManager.AdjustableHoeRadiusEnabled.Value || __0 == null || __result == null) { return; } int pos = __0.GetPos(); if (pos < 4 || __0.Size() - pos < 4) { return; } if (__0.ReadInt() != 1297371720) { __0.SetPos(pos); return; } if (__0.Size() - __0.GetPos() < 12) { log.Warn("Received incomplete terrain radius data. Using vanilla settings."); __0.SetPos(pos); return; } int num = __0.ReadInt(); int num2 = __0.ReadInt(); float num3 = __0.ReadSingle(); int pos2 = __0.GetPos(); __0.SetPos(pos - 4); int num4 = __0.ReadInt(); __0.SetPos(pos2); float num5 = ((num2 == StringExtensionMethods.GetStableHashCode("path_v2")) ? 2f : 1f); if (num != 1 || num4 != num2 || !SupportedTerrainHashes.Contains(num2) || float.IsNaN(num3) || float.IsInfinity(num3) || num3 < num5 || num3 > 7f) { log.Warn("Rejected invalid terrain radius data. Using vanilla settings."); __0.SetPos(pos); return; } if (__result.m_raise || (!__result.m_level && !__result.m_smooth && !__result.m_paintCleared)) { log.Warn("Received radius data for an unexpected terrain operation. Using vanilla settings."); __0.SetPos(pos); return; } float effectiveRadius = GetEffectiveRadius(__result); if (effectiveRadius <= 0f) { log.Warn("Received terrain operation has no valid radius. Using vanilla settings."); __0.SetPos(pos); return; } Settings val = CloneSettings(__result); float num6 = num3 / effectiveRadius; if (val.m_level) { val.m_levelRadius *= num6; } if (val.m_raise) { val.m_raiseRadius *= num6; } if (val.m_smooth) { val.m_smoothRadius *= num6; } if (val.m_paintCleared) { val.m_paintRadius *= num6; } __result = val; log.Info($"Applied network terrain radius: Hash={num2}, Radius={num3:0.##}m, Level={val.m_levelRadius:0.##}, Smooth={val.m_smoothRadius:0.##}, Paint={val.m_paintRadius:0.##}."); } } private static readonly LogManager log = new LogManager("Hoe Radius", LogManager.LogLevel.Warning); private const float RadiusStep = 1f; private const float MinRadius = 1f; private const float PathenMinRadius = 2f; private const float MaxRadius = 7f; private const int RadiusWireMagic = 1297371720; private const int RadiusWireVersion = 1; private static readonly HashSet<int> SupportedTerrainHashes = new HashSet<int> { StringExtensionMethods.GetStableHashCode("mud_road_v2"), StringExtensionMethods.GetStableHashCode("path_v2"), StringExtensionMethods.GetStableHashCode("paved_road_v2"), StringExtensionMethods.GetStableHashCode("MarsarahTweaks_Paving"), StringExtensionMethods.GetStableHashCode("cultivate_v2"), StringExtensionMethods.GetStableHashCode("replant_v2") }; private static TerrainOp activeOperation; private static float originalLevel; private static float originalRaise; private static float originalSmooth; private static float originalPaint; private static float defaultRadius; private static float currentRadius; private static Transform previewTransform; private static Vector3 originalPreviewScale; private static Transform pathenParticleTransform; private static Vector3 originalPathenParticleScale; private static bool interceptPlacementScroll; private static bool suppressCameraZoom; private static readonly FieldRef<Player, PieceTable> buildPiecesRef = AccessTools.FieldRefAccess<Player, PieceTable>("m_buildPieces"); private static readonly Dictionary<string, float> savedRadii = new Dictionary<string, float>(); private static bool TryGetSupportedOperation(Player player, PieceTable pieceTable, out TerrainOp operation) { operation = null; if ((Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)pieceTable == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hoe"); GameObject itemPrefab2 = ObjectDB.instance.GetItemPrefab("Cultivator"); PieceTable val = ((itemPrefab == null) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces); PieceTable val2 = ((itemPrefab2 == null) ? null : itemPrefab2.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces); bool flag = (Object)(object)val != (Object)null && (Object)(object)pieceTable == (Object)(object)val; bool flag2 = (Object)(object)val2 != (Object)null && (Object)(object)pieceTable == (Object)(object)val2; if (!flag && !flag2) { return false; } GameObject selectedPrefab = pieceTable.GetSelectedPrefab(); if ((Object)(object)selectedPrefab == (Object)null) { return false; } string name = ((Object)selectedPrefab).name; bool num; if (!flag) { if (name == "cultivate_v2") { goto IL_0191; } num = name == "replant_v2"; } else { switch (name) { case "mud_road_v2": case "path_v2": case "paved_road_v2": goto IL_0191; } num = name == "MarsarahTweaks_Paving"; } if (!num) { return false; } goto IL_0191; IL_0191: operation = selectedPrefab.GetComponent<TerrainOp>(); return (Object)(object)operation != (Object)null && operation.m_settings != null; } private static void SelectOperation(TerrainOp operation) { RestoreOriginalSettings(); activeOperation = operation; Settings settings = operation.m_settings; originalLevel = settings.m_levelRadius; originalRaise = settings.m_raiseRadius; originalSmooth = settings.m_smoothRadius; originalPaint = settings.m_paintRadius; defaultRadius = 0f; if (settings.m_level) { defaultRadius = Mathf.Max(defaultRadius, originalLevel); } if (settings.m_raise) { defaultRadius = Mathf.Max(defaultRadius, originalRaise); } if (settings.m_smooth) { defaultRadius = Mathf.Max(defaultRadius, originalSmooth); } if (settings.m_paintCleared) { defaultRadius = Mathf.Max(defaultRadius, originalPaint); } if (defaultRadius <= 0f) { log.Warn("No active terrain radius found for '" + ((Object)operation).name + "'."); activeOperation = null; return; } if (savedRadii.TryGetValue(((Object)((Component)operation).gameObject).name, out var value)) { currentRadius = Mathf.Clamp(value, GetMinimumRadius(operation), 7f); ApplyRadius(settings, currentRadius / defaultRadius); } else { currentRadius = defaultRadius; } log.Info($"Selected '{((Object)operation).name}' with radius {currentRadius:0.##}m."); } private static void ApplyRadius(Settings settings, float scale) { if (settings != null) { settings.m_levelRadius = (settings.m_level ? (originalLevel * scale) : originalLevel); settings.m_raiseRadius = (settings.m_raise ? (originalRaise * scale) : originalRaise); settings.m_smoothRadius = (settings.m_smooth ? (originalSmooth * scale) : originalSmooth); settings.m_paintRadius = (settings.m_paintCleared ? (originalPaint * scale) : originalPaint); } } private static void UpdatePreview(GameObject ghost) { //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019b: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_011d: 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_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Invalid comparison between Unknown and I4 //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ghost == (Object)null || (Object)(object)activeOperation == (Object)null || defaultRadius <= 0f) { return; } float num = currentRadius / defaultRadius; TerrainOp component = ghost.GetComponent<TerrainOp>(); if ((Object)(object)component != (Object)null) { ApplyRadius(component.m_settings, num); } Transform val = ghost.transform.Find("_GhostOnly"); if ((Object)(object)val == (Object)null) { val = ghost.transform.Find("GhostOnly"); } if ((Object)(object)val != (Object)(object)previewTransform) { RestorePreviewScale(); previewTransform = val; if ((Object)(object)previewTransform != (Object)null) { originalPreviewScale = previewTransform.localScale; if (((Object)activeOperation).name == "path_v2") { ParticleSystem componentInChildren = ((Component)previewTransform).GetComponentInChildren<ParticleSystem>(true); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)((Component)componentInChildren).transform != (Object)(object)previewTransform) { MainModule main = componentInChildren.main; if ((int)((MainModule)(ref main)).scalingMode == 1) { pathenParticleTransform = ((Component)componentInChildren).transform; originalPathenParticleScale = pathenParticleTransform.localScale; log.Info("Detected Pathen's local-scaled ghost particle."); goto IL_017f; } } log.Warn("Could not find Pathen's expected local-scaled ghost particle."); } } } goto IL_017f; IL_017f: if ((Object)(object)previewTransform != (Object)null) { previewTransform.localScale = originalPreviewScale * num; } if ((Object)(object)pathenParticleTransform != (Object)null) { pathenParticleTransform.localScale = originalPathenParticleScale * num; } } private static void RestorePreviewScale() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)pathenParticleTransform != (Object)null) { pathenParticleTransform.localScale = originalPathenParticleScale; } pathenParticleTransform = null; if ((Object)(object)previewTransform != (Object)null) { previewTransform.localScale = originalPreviewScale; } previewTransform = null; } private static void RestoreOriginalSettings() { if ((Object)(object)activeOperation != (Object)null) { Settings settings = activeOperation.m_settings; settings.m_levelRadius = originalLevel; settings.m_raiseRadius = originalRaise; settings.m_smoothRadius = originalSmooth; settings.m_paintRadius = originalPaint; } RestorePreviewScale(); activeOperation = null; defaultRadius = 0f; currentRadius = 0f; } private static float GetMinimumRadius(TerrainOp operation) { return ((Object)(object)operation != (Object)null && ((Object)operation).name == "path_v2") ? 2f : 1f; } private static float GetEffectiveRadius(Settings settings) { float num = 0f; if (settings.m_level) { num = Mathf.Max(num, settings.m_levelRadius); } if (settings.m_raise) { num = Mathf.Max(num, settings.m_raiseRadius); } if (settings.m_smooth) { num = Mathf.Max(num, settings.m_smoothRadius); } if (settings.m_paintCleared) { num = Mathf.Max(num, settings.m_paintRadius); } return num; } private static Settings CloneSettings(Settings source) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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) //IL_0066: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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_0102: 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_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Expected O, but got Unknown return new Settings { m_levelOffset = source.m_levelOffset, m_level = source.m_level, m_levelRadius = source.m_levelRadius, m_square = source.m_square, m_raise = source.m_raise, m_raiseRadius = source.m_raiseRadius, m_raisePower = source.m_raisePower, m_raiseDelta = source.m_raiseDelta, m_smooth = source.m_smooth, m_smoothRadius = source.m_smoothRadius, m_smoothPower = source.m_smoothPower, m_paintCleared = source.m_paintCleared, m_paintHeightCheck = source.m_paintHeightCheck, m_paintType = source.m_paintType, m_paintRadius = source.m_paintRadius, m_paintStrength = source.m_paintStrength, m_paintExp = source.m_paintExp, m_paintCurve = source.m_paintCurve, m_rotation = source.m_rotation, m_sides = source.m_sides, m_addMedianMax = source.m_addMedianMax, m_centerMultiplicationFactor = source.m_centerMultiplicationFactor, m_pointMultiplicationFactor = source.m_pointMultiplicationFactor, m_halfOffset = source.m_halfOffset }; } } internal static class MoreUsableFuel { [HarmonyPatch(typeof(Smelter), "Awake")] public static class AddAncientBarkToKiln_Patch { private static void Postfix(Smelter __instance) { UpdateKiln(__instance); } } [HarmonyPatch(typeof(ShieldGenerator), "Start")] public static class AddWitheredBonesToShieldGenerator_Patch { private static void Postfix(ShieldGenerator __instance) { UpdateShieldGenerator(__instance); } } private static readonly LogManager log = new LogManager("More Usable Fuel", LogManager.LogLevel.Warning); public static void UpdateMoreUsableFuel() { UpdateAllKilns(); UpdateAllShieldGenerators(); } private static void UpdateAllKilns() { Smelter[] array = Object.FindObjectsByType<Smelter>((FindObjectsSortMode)0); foreach (Smelter kiln in array) { UpdateKiln(kiln); } } private static void UpdateKiln(Smelter kiln) { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Expected O, but got Unknown if (!kiln.m_conversion.Exists((ItemConversion conv) => (Object)(object)conv.m_to != (Object)null && ((Object)conv.m_to).name == "Coal")) { return; } ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab("ElderBark") : null); ObjectDB instance2 = ObjectDB.instance; GameObject val2 = ((instance2 != null) ? instance2.GetItemPrefab("Coal") : null); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2)) { log.Warn("Missing prefab: AncientBark or Coal."); return; } ItemDrop barkDrop = val.GetComponent<ItemDrop>(); ItemDrop coalDrop = val2.GetComponent<ItemDrop>(); ItemConversion val3 = ((IEnumerable<ItemConversion>)kiln.m_conversion).FirstOrDefault((Func<ItemConversion, bool>)((ItemConversion conv) => (Object)(object)conv.m_from == (Object)(object)barkDrop && (Object)(object)conv.m_to == (Object)(object)coalDrop)); if (ConfigManager.MoreUsableFuelEnabled.Value) { if (val3 == null) { ItemConversion item = new ItemConversion { m_from = barkDrop, m_to = coalDrop }; kiln.m_conversion.Add(item); log.Info("Added Ancient Bark as fuel for Kiln."); } } else if (val3 != null) { kiln.m_conversion.Remove(val3); log.Info("Removed Ancient Bark as fuel from Kiln."); } } private static void UpdateAllShieldGenerators() { ShieldGenerator[] array = Object.FindObjectsByType<ShieldGenerator>((FindObjectsSortMode)0); foreach (ShieldGenerator sg in array) { UpdateShieldGenerator(sg); } } private static void UpdateShieldGenerator(ShieldGenerator sg) { ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab("WitheredBone") : null); if (!Object.op_Implicit((Object)(object)val)) { log.Warn("WitheredBone prefab not found."); return; } ItemDrop component = val.GetComponent<ItemDrop>(); if (!Object.op_Implicit((Object)(object)component)) { log.Warn("WitheredBone does not have ItemDrop component."); } else if (ConfigManager.MoreUsableFuelEnabled.Value) { if (!sg.m_fuelItems.Contains(component)) { sg.m_fuelItems.Add(component); log.Info("Added WitheredBone as fuel for Shield Generator."); } } else if (sg.m_fuelItems.Contains(component)) { sg.m_fuelItems.Remove(component); log.Info("Removed WitheredBone as fuel from Shield Generator."); } } } internal class BoatRadiusChanges { [HarmonyPatch(typeof(Minimap), "UpdateExplore")] private class LargerBoatExploreRadius_Patch { private static float originalExploreRadius = -1f; private static void Prefix(ref float ___m_exploreRadius) { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) { return; } if (ConfigManager.LargerBoatExploreRadiusEnabled.Value) { if (Object.op_Implicit((Object)(object)Ship.GetLocalShip()) && Ship.GetLocalShip().HasPlayerOnboard()) { if (originalExploreRadius == -1f) { log.Info($"Backing up explore radius: {___m_exploreRadius}"); originalExploreRadius = ___m_exploreRadius; } if (___m_exploreRadius != 100f) { log.Info("Applying new explore radius: 100"); ___m_exploreRadius = 100f; } } else if (originalExploreRadius != -1f && ___m_exploreRadius != originalExploreRadius) { log.Info($"Restoring original explore radius: {originalExploreRadius}"); ___m_exploreRadius = originalExploreRadius; } } else if (originalExploreRadius != -1f && ___m_exploreRadius != originalExploreRadius) { log.Info($"Restoring original explore radius: {originalExploreRadius} due to config OFF"); ___m_exploreRadius = originalExploreRadius; } } } private static readonly LogManager log = new LogManager("Boat Radius", LogManager.LogLevel.Warning); } internal class FasterEquipChanges { [HarmonyPatch(typeof(Player), "QueueEquipAction")] private static class EquipActionSpeed_Patch { private static void Prefix(ItemData item) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) || !ConfigManager.FasterEquipEnabled.Value) { return; } if (item.IsWeapon()) { if (item.m_shared.m_equipDuration > 0f) { item.m_shared.m_equipDuration = 0f; } log.Info($"Weapon {item.m_shared.m_name} - anim state: {item.m_shared.m_animationState}"); } if (item.IsEquipable() && !item.IsWeapon() && item.m_shared.m_equipDuration > 1f) { item.m_shared.m_equipDuration = 1f; } } } [HarmonyPatch(typeof(Player), "QueueUnequipAction")] private static class UnequipActionSpeed_Patch { private static void Prefix(ItemData item) { if ((!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated()) && ConfigManager.FasterEquipEnabled.Value) { if (item.IsWeapon() && item.m_shared.m_equipDuration > 0f) { item.m_shared.m_equipDuration = 0f; } if (item.IsEquipable() && !item.IsWeapon() && item.m_shared.m_equipDuration > 1f) { item.m_shared.m_equipDuration = 1f; } } } } [HarmonyPatch(typeof(ZSyncAnimation), "SetTrigger")] private class RemoveEquipAndEatAnimation { private static bool Prefix(ZSyncAnimation __instance, string name) { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) { return true; } if (ConfigManager.FasterEquipEnabled.Value && name == "equip_hip") { return false; } return true; } } private static readonly LogManager log = new LogManager("Faster Equip", LogManager.LogLevel.Warning); } internal class FasterResourceDrops { [HarmonyPatch(typeof(Ragdoll), "Awake")] private class FasterResourceDrops_Patch { public static void Prefix(Ragdoll __instance, ref float ___m_ttl) { if (!((Object)(object)__instance == (Object)null) && ConfigManager.FasterResourceDropsEnabled.Value) { if (___m_ttl > 5f) { ___m_ttl = 5f; log.Info("Large monster ttl set to 5s"); } else if (___m_ttl > 0.5f) { ___m_ttl = 0.5f; log.Info("Small monster ttl set to 0.5s"); } } } } private static readonly LogManager log = new LogManager("Faster Resource Drops", LogManager.LogLevel.Warning); } internal class FriendlyBallistas { [HarmonyPatch(typeof(Turret), "UpdateTarget")] private class FriendlyBallistas_Patch { private static bool originalTargetsFriendly = true; private static readonly bool newTargetsFriendly = false; private static void Postfix([NotNull] ref bool ___m_targetPlayers, [NotNull] ref bool ___m_targetTamed) { if (ConfigManager.FriendlyBallistasEnabled.Value) { if (___m_targetPlayers != newTargetsFriendly) { log.Info($"Applying new player targeting: {newTargetsFriendly}"); ___m_targetPlayers = newTargetsFriendly; } if (___m_targetTamed != newTargetsFriendly) { log.Info($"Applying new tamed targeting: {newTargetsFriendly}"); ___m_targetTamed = newTargetsFriendly; } } else { if (___m_targetPlayers != originalTargetsFriendly) { log.Info($"Restoring player targeting: {originalTargetsFriendly}"); ___m_targetPlayers = originalTargetsFriendly; } if (___m_targetTamed != originalTargetsFriendly) { log.Info($"Restoring tamed targeting: {originalTargetsFriendly}"); ___m_targetTamed = originalTargetsFriendly; } } } } private static readonly LogManager log = new LogManager("Friendly Ballistas", LogManager.LogLevel.Warning); } internal class LargerPickupAreaChanges { [HarmonyPatch(typeof(Player), "Awake")] private class LargerPickupArea_Patch { private static void Prefix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated())) { UpdatePickupArea(__instance, wasChanged: false); } } } private static readonly LogManager log = new LogManager("Larger Pickup Area", LogManager.LogLevel.Warning); private static float originalPickupArea = -1f; public static void UpdatePickupArea(Player player, bool wasChanged) { if (ConfigManager.LargerPickupAreaEnabled.Value) { if (originalPickupArea == -1f) { log.Info($"Backing up pickup area ({player.m_autoPickupRange})"); originalPickupArea = player.m_autoPickupRange; } log.Info($"Assigning new pickup area (3) - from {player.m_autoPickupRange}"); player.m_autoPickupRange = 3f; } else if (wasChanged && originalPickupArea != -1f) { log.Info($"Restoring pickup area: {originalPickupArea} - from {player.m_autoPickupRange}"); player.m_autoPickupRange = originalPickupArea; } } } internal class LessFallDamage { [HarmonyPatch(typeof(SEMan), "ModifyFallDamage")] private class FallDamage_Patch { private static void Prefix(ref float damage) { if ((!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated()) && ConfigManager.LessFallDamageEnabled.Value) { log.Info("Reducing fall damage by 40%"); damage *= 0.6f; } } } private static readonly LogManager log = new LogManager("Less Fall Damage", LogManager.LogLevel.Warning); } internal class LighterMetalWeight { [HarmonyPatch(typeof(ObjectDB), "Awake")] private class OthersSection_Patch { private static void Postfix(ref ObjectDB __instance) { if (!((Object)(object)__instance == (Object)null) && (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated())) { UpdateLighterMetalWeight(__instance, wasChanged: false); } } } private static readonly LogManager log = new LogManager("Lighter Metal Weight", LogManager.LogLevel.Warning); private static readonly Dictionary<string, float> metalWeightOriginals = new Dictionary<string, float>(); private static readonly Dictionary<string, float> metalWeightChanges = new Dictionary<string, float> { { "TinOre", 8f }, { "Tin", 8f }, { "CopperOre", 8f }, { "Copper", 8f }, { "Bronze", 8f }, { "IronOre", 8f }, { "IronScrap", 8f }, { "Iron", 8f }, { "SilverOre", 8f }, { "Silver", 8f }, { "BlackMetalScrap", 8f }, { "BlackMetal", 8f }, { "CopperScrap", 8f }, { "BronzeScrap", 8f }, { "Flametal", 8f }, { "FlametalNew", 8f }, { "FlametalOre", 8f }, { "FlametalOreNew", 8f } }; public static void UpdateLighterMetalWeight(ObjectDB objDB, bool wasChanged) { if (ConfigManager.LighterMetalWeightEnabled.Value) { foreach (string itemName in metalWeightChanges.Keys) { GameObject val = objDB.m_items.Find((GameObject i) => ((Object)i).name == itemName); if (!((Object)(object)val == (Object)null)) { ItemDrop component = val.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null)) { if (!metalWeightOriginals.ContainsKey(((Object)val).name)) { metalWeightOriginals[((Object)val).name] = component.m_itemData.m_shared.m_weight; } if (metalWeightChanges.TryGetValue(((Object)val).name, out var value)) { log.Info($"Applying new weight for {((Object)val).name} from {component.m_itemData.m_shared.m_weight} to {value}"); component.m_itemData.m_shared.m_weight = value; } } } } return; } if (!wasChanged) { return; } foreach (string itemName2 in metalWeightOriginals.Keys) { GameObject val2 = objDB.m_items.Find((GameObject i) => ((Object)i).name == itemName2); if (!((Object)(object)val2 == (Object)null)) { ItemDrop component2 = val2.GetComponent<ItemDrop>(); if (!((Object)(object)component2 == (Object)null) && metalWeightOriginals.TryGetValue(((Object)val2).name, out var value2)) { log.Info($"Restoring original value for {((Object)val2).name} from {component2.m_itemData.m_shared.m_weight} to {value2}"); component2.m_itemData.m_shared.m_weight = value2; } } } metalWeightOriginals.Clear(); } } internal class NoSkillLossChanges { [HarmonyPatch(typeof(Skills), "Awake")] private class NoSkillLowerOnDeath_Patch { private static void Prefix(ref float ___m_DeathLowerFactor) { if ((!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated()) && ConfigManager.NoSkillLowerOnDeathEnabled.Value) { log.Info("Updating death lower factor"); ___m_DeathLowerFactor = 0f; } } } private static readonly LogManager log = new LogManager("No Skill Loss", LogManager.LogLevel.Warning); } internal class PavingChanges { [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class PavingPrefab_Patch { private static void Postfix(ZNetScene __instance) { if (!((Object)(object)__instance == (Object)null)) { RegisterPavingPrefab(__instance); UpdatePavingAvailability(__instance); } } } [HarmonyPatch(typeof(ObjectDB), "UpdateRegisters")] private static class PavingTerrainOpRegistry_Patch { private static void Postfix(ObjectDB __instance) { RegisterPavingTerrainOp(__instance); } } [HarmonyPatch(typeof(ZNetScene), "OnDestroy")] private static class PavingCleanup_Patch { private static void Prefix(ZNetScene __instance) { if (pavingPrefab == null) { return; } GameObject prefab = __instance.GetPrefab("Hoe"); PieceTable val = ((prefab == null) ? null : prefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces); if ((Object)(object)val != (Object)null) { int num = val.m_pieces.RemoveAll((GameObject val2) => val2 == pavingPrefab); if (num > 0) { log.Info($"Removed {num} Paving prefab reference(s) from the Hoe PieceTable during world shutdown."); } } else { log.Warn("Could not access the Hoe PieceTable during Paving cleanup."); } pavingPrefab = null; } } private static readonly LogManager log = new LogManager("Paving", LogManager.LogLevel.Warning); private const string SourcePrefabName = "paved_road_v2"; private const string PavingPrefabName = "MarsarahTweaks_Paving"; private const string HoePrefabName = "Hoe"; private static readonly FieldRef<ZNetScene, Dictionary<int, GameObject>> namedPrefabsRef = AccessTools.FieldRefAccess<ZNetScene, Dictionary<int, GameObject>>("m_namedPrefabs"); private static GameObject pavingPrefab; private static void RegisterPavingPrefab(ZNetScene znScene) { //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Expected O, but got Unknown //IL_039f: Unknown result type (might be due to invalid IL or missing references) Dictionary<int, GameObject> dictionary = namedPrefabsRef.Invoke(znScene); int stableHashCode = StringExtensionMethods.GetStableHashCode("MarsarahTweaks_Paving"); if (dictionary.TryGetValue(stableHashCode, out var value)) { if (((Object)value).name == "MarsarahTweaks_Paving") { pavingPrefab = value; RegisterPavingTerrainOp(ObjectDB.instance); } else { log.Error("Prefab hash collision for 'MarsarahTweaks_Paving'."); } return; } GameObject prefab = znScene.GetPrefab("Hoe"); PieceTable val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_buildPieces; if ((Object)(object)val == (Object)null) { log.Error("Could not find the Hoe PieceTable."); return; } GameObject val2 = val.m_pieces.Find((GameObject val5) => (Object)(object)val5 != (Object)null && ((Object)val5).name == "paved_road_v2"); if ((Object)(object)val2 == (Object)null) { log.Error("Could not find 'paved_road_v2' in the Hoe PieceTable."); { foreach (GameObject piece in val.m_pieces) { if ((Object)(object)piece != (Object)null && ((Object)piece).name.Contains("paved")) { log.Info($"Available paved-road candidate: '{((Object)piece).name}', TerrainOp={(Object)(object)piece.GetComponent<TerrainOp>() != (Object)null}."); } } return; } } log.Info("Found active Hoe prefab '" + ((Object)val2).name + "'."); GameObject val3 = new GameObject("MarsarahTweaks_Paving_CloneContainer"); val3.transform.SetParent(((Component)znScene).transform, false); val3.SetActive(false); GameObject val4 = Object.Instantiate<GameObject>(val2, val3.transform); ((Object)val4).name = "MarsarahTweaks_Paving"; val4.SetActive(true); log.Info(string.Format("Created Paving prefab from '{0}'. ActiveSelf={1}, ActiveInHierarchy={2}.", "paved_road_v2", val4.activeSelf, val4.activeInHierarchy)); Piece component = val4.GetComponent<Piece>(); TerrainOp component2 = val4.GetComponent<TerrainOp>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null) { log.Error("Could not create 'MarsarahTweaks_Paving': source prefab is missing Piece or TerrainOp."); Object.Destroy((Object)(object)val3); return; } if (component2.m_settings.m_paintRadius <= 0f) { log.Error("Could not create 'MarsarahTweaks_Paving': source prefab has no valid paint radius."); Object.Destroy((Object)(object)val3); return; } component.m_name = "Paving Without Leveling"; component.m_description = "Pave the ground without leveling it."; component2.m_settings.m_level = false; component2.m_settings.m_raise = false; component2.m_settings.m_smooth = false; component2.m_settings.m_paintCleared = true; log.Info($"Paving terrain operation: Level={component2.m_settings.m_level}, Raise={component2.m_settings.m_raise}, Smooth={component2.m_settings.m_smooth}, Paint={component2.m_settings.m_paintCleared}, PaintType={component2.m_settings.m_paintType}, PaintRadius={component2.m_settings.m_paintRadius}."); if ((Object)(object)val4.GetComponent<ZNetView>() != (Object)null) { znScene.m_prefabs.Add(val4); } else { znScene.m_nonNetViewPrefabs.Add(val4); } dictionary.Add(stableHashCode, val4); pavingPrefab = val4; RegisterPavingTerrainOp(ObjectDB.instance); log.Info($"Paving registered successfully. ActiveSelf={val4.activeSelf}, ActiveInHierarchy={val4.activeInHierarchy}, TerrainOp={(Object)(object)component2 != (Object)null}."); } public static void UpdatePavingAvailability(ZNetScene znScene) { if ((Object)(object)znScene == (Object)null || (Object)(object)pavingPrefab == (Object)null) { return; } GameObject prefab = znScene.GetPrefab("Hoe"); if ((Object)(object)prefab == (Object)null) { log.Error("Could not find Hoe prefab."); return; } PieceTable val = prefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces; if ((Object)(object)val == (Object)null) { log.Error("Could not find Hoe PieceTable."); return; } bool flag = val.m_pieces.Contains(pavingPrefab); if (ConfigManager.PavingEnabled.Value && !flag) { int num = val.m_pieces.FindIndex((GameObject val2) => (Object)(object)val2 != (Object)null && ((Object)val2).name == "paved_road_v2"); if (num >= 0) { val.m_pieces.Insert(num + 1, pavingPrefab); } else { val.m_pieces.Add(pavingPrefab); } log.Info("Added Paving to the Hoe build menu."); } else if (!ConfigManager.PavingEnabled.Value && flag) { val.m_pieces.Remove(pavingPrefab); log.Info("Removed Paving from the Hoe build menu."); } } private static void RegisterPavingTerrainOp(ObjectDB objectDB) { if ((Object)(object)objectDB == (Object)null || (Object)(object)pavingPrefab == (Object)null) { return; } TerrainOp component = pavingPrefab.GetComponent<TerrainOp>(); if ((Object)(object)component == (Object)null) { log.Error("Cannot register Paving TerrainOp: component is missing."); return; } int prefabHash = objectDB.GetPrefabHash(pavingPrefab); if (objectDB.m_terrainOpsByHash.TryGetValue(prefabHash, out var value)) { if ((Object)(object)value != (Object)(object)component) { log.Error(string.Format("TerrainOp hash collision for '{0}' ({1}).", "MarsarahTweaks_Paving", prefabHash)); return; } } else { objectDB.m_terrainOpsByHash.Add(prefabHash, component); log.Info($"Registered Paving TerrainOp with hash {prefabHash}."); } if (!objectDB.m_terrainOps.Contains(component)) { objectDB.m_terrainOps.Add(component); } } } internal class PermanentLightsChanges { [HarmonyPatch(typeof(Fireplace), "UpdateFireplace")] private static class Fireplace_UpdateFireplace_Patch { private static void Postfix(Fireplace __instance, ZNetView ___m_nview) { string prefabName = Utils.GetPrefabName(((Component)__instance).gameObject); bool flag = IsFire(__instance, prefabName); if (prefabName == "fire_pit") { __instance.m_maxFuel = (CoversFires ? 5f : 10f); } else if (prefabName == "hearth") { __instance.m_maxFuel = (CoversFires ? 10f : 20f); } if (CoversFireplaces && (!flag || CoversFires)) { Refill(___m_nview, __instance.m_maxFuel); } } } [HarmonyPatch(typeof(CookingStation), "UpdateCooking")] private static class CookingStation_UpdateCooking_Patch { private static void Postfix(CookingStation __instance, ZNetView ___m_nview) { if (CoversUtilities && __instance.m_useFuel && !(Utils.GetPrefabName(((Component)__instance).gameObject) != "piece_oven")) { Refill(___m_nview, __instance.m_maxFuel); } } } [HarmonyPatch(typeof(Smelter), "UpdateSmelter")] private static class Smelter_UpdateSmelter_Patch { private static void Postfix(Smelter __instance, ZNetView ___m_nview) { if (CoversUtilities && !(Utils.GetPrefabName(((Component)__instance).gameObject) != "piece_bathtub")) { Refill(___m_nview, __instance.m_maxFuel); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class PermanentLightsBuildPieces_Patch { private static void Postfix(ZNetScene __instance) { if (!((Object)(object)__instance == (Object)null) && (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated())) { UpdateLightBuildPiecesAmounts(__instance, wasChanged: false); } } } private static readonly LogManager log = new LogManager("Permanent Lights", LogManager.LogLevel.Warning); private const int CampfirePermanentFuel = 5; private const int HearthPermanentFuel = 10; private static readonly Dictionary<string, Requirement[]> originalLightPieceCosts = new Dictionary<string, Requirement[]>(); public static readonly Dictionary<string, Dictionary<string, int>> lightPieceCostChanges = new Dictionary<string, Dictionary<string, int>> { { "$piece_firepit", new Dictionary<string, int> { { "Wood", 5 } } }, { "$piece_hearth", new Dictionary<string, int> { { "Wood", 10 } } }, { "$piece_sconce", new Dictionary<string, int> { { "Resin", 6 } } }, { "$piece_groundtorch", new Dictionary<string, int> { { "Resin", 6 } } }, { "$piece_groundtorchwood", new Dictionary<string, int> { { "Resin", 4 } } }, { "$piece_groundtorchgreen", new Dictionary<string, int> { { "Guck", 6 } } }, { "$piece_groundtorchblue", new Dictionary<string, int> { { "GreydwarfEye", 6 } } }, { "$piece_brazierfloor01", new Dictionary<string, int> { { "Coal", 5 } } }, { "$piece_brazierfloor02", new Dictionary<string, int> { { "GreydwarfEye", 5 } } }, { "$piece_brazierceiling01", new Dictionary<string, int> { { "Coal", 5 } } } }; private static bool CoversFireplaces => ConfigManager.PermanentLightsMode.Value != "Off"; private static bool CoversFires => ConfigManager.PermanentLightsMode.Value == "Lights & Fires" || ConfigManager.PermanentLightsMode.Value == "Lights, Fires, Stoves & Hot Tubs"; private static bool CoversUtilities => ConfigManager.PermanentLightsMode.Value == "Lights, Fires, Stoves & Hot Tubs"; private static bool IsFire(Fireplace fireplace, string prefabName) { string text = ((Component)fireplace).GetComponent<Piece>()?.m_name; switch (text) { default: if (!(text == "$piece_bonfire")) { return prefabName.IndexOf("fire_pit", StringComparison.OrdinalIgnoreCase) >= 0 || prefabName.IndexOf("firepit", StringComparison.OrdinalIgnoreCase) >= 0 || prefabName.IndexOf("hearth", StringComparison.OrdinalIgnoreCase) >= 0 || prefabName.IndexOf("bonfire", StringComparison.OrdinalIgnoreCase) >= 0; } goto case "$piece_firepit"; case "$piece_firepit": case "$piece_firepit_iron": case "$piece_hearth": return true; } } private static void Refill(ZNetView nview, float maxFuel) { if (!((Object)(object)nview == (Object)null) && nview.IsOwner() && !(maxFuel <= 0f)) { ZDO zDO = nview.GetZDO(); if (zDO != null && !(zDO.GetFloat("fuel", 0f) >= maxFuel)) { zDO.Set("fuel", maxFuel); } } } private static Requirement CopyRequirement(Requirement req) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown return new Requirement { m_resItem = req.m_resItem, m_amount = req.m_amount, m_amountPerLevel = req.m_amountPerLevel, m_recover = req.m_recover }; } private static GameObject FindPiecePrefab(ZNetScene scene, string pieceName) { if (pieceName == "$piece_firepit") { return scene.m_prefabs.Find((GameObject p) => ((Object)p).name == "fire_pit" && p.GetComponent<Piece>()?.m_name == pieceName); } return scene.m_prefabs.Find((GameObject p) => p.GetComponent<Piece>()?.m_name == pieceName); } public static void UpdateLightBuildPiecesAmounts(ZNetScene znScene, bool wasChanged) { //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Expected O, but got Unknown if ((Object)(object)znScene == (Object)null) { return; } foreach (KeyValuePair<string, Dictionary<string, int>> lightPieceCostChange in lightPieceCostChanges) { string key = lightPieceCostChange.Key; bool flag = ((key == "$piece_firepit" || key == "$piece_hearth") ? CoversFires : CoversFireplaces); Requirement[] value; bool flag2 = originalLightPieceCosts.TryGetValue(key, out value); if (!flag && !flag2) { continue; } GameObject val = FindPiecePrefab(znScene, key); Piece val2 = ((val != null) ? val.GetComponent<Piece>() : null); if ((Object)(object)val2 == (Object)null) { if (flag) { log.Warn(key + " prefab not found in ZNetScene."); } continue; } if (!flag) { val2.m_resources = value.Select(CopyRequirement).ToArray(); originalLightPieceCosts.Remove(key); log.Info("Restored build costs for " + key + "."); continue; } if (!flag2) { originalLightPieceCosts[key] = val2.m_resources.Select(CopyRequirement).ToArray(); } Requirement[] resources = val2.m_resources; foreach (Requirement val3 in resources) { if ((Object)(object)val3.m_resItem != (Object)null && lightPieceCostChange.Value.TryGetValue(((Object)val3.m_resItem).name, out var value2)) { val3.m_amount = value2; if (((Object)val3.m_resItem).name == "Wood") { val3.m_recover = true; } } } if (key == "$piece_hearth" && !val2.m_resources.Any((Requirement req) => (Object)(object)req.m_resItem != (Object)null && ((Object)req.m_resItem).name == "Wood")) { GameObject prefab = znScene.GetPrefab("Wood"); ItemDrop val4 = ((prefab != null) ? prefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val4 != (Object)null) { val2.m_resources = val2.m_resources.Append(new Requirement { m_amount = 10, m_amountPerLevel = 0, m_resItem = val4, m_recover = true }).ToArray(); log.Info("Added the Hearth's wood build requirement."); } else { log.Warn("Could not find Wood prefab for the Hearth build requirement."); } } } } } internal static class PlayerLogoutAnnounce { [HarmonyPatch(typeof(ZNet), "Update")] private static class ZNetUpdatePatch { private static void Postfix() { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } List<ZNetPeer> connectedPeers = ZNet.instance.GetConnectedPeers(); HashSet<string> hashSet = new HashSet<string>(); foreach (ZNetPeer item in connectedPeers) { if (!string.IsNullOrEmpty(item.m_playerName)) { hashSet.Add(item.m_playerName); } } if (ConfigManager.AnnouncePlayerLogout.Value) { foreach (string previousPeer in previousPeers) { if (!hashSet.Contains(previousPeer)) { log.Info(previousPeer + " logged out."); ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(0L, "MarsarahTweaks_LogoutAnnounce", new object[1] { previousPeer }); } } } } previousPeers = hashSet; } } [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetSceneAwakePatch { private static void Postfix() { TryRegisterRPC(); } } private static readonly LogManager log = new LogManager("Player Logout Announce", LogManager.LogLevel.Warning); private const string LogoutRPC = "MarsarahTweaks_LogoutAnnounce"; private static HashSet<string> previousPeers = new HashSet<string>(); private static ZRoutedRpc registeredRpc; private static void TryRegisterRPC() { if (ZRoutedRpc.instance != null && registeredRpc != ZRoutedRpc.instance) { ZRoutedRpc.instance.Register<string>("MarsarahTweaks_LogoutAnnounce", (Action<long, string>)OnPlayerLogoutRPC); registeredRpc = ZRoutedRpc.instance; previousPeers.Clear(); log.Info("Registered Player Logout Announce RPC."); } } private static void OnPlayerLogoutRPC(long sender, string playerName) { if (ConfigManager.AnnouncePlayerLogout.Value) { MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)1, playerName + " logged out.", 0, (Sprite)null, false, true); } Chat instance2 = Chat.instance; if (instance2 != null) { ((Terminal)instance2).AddString("[Server]", playerName + " logged out.", (Type)2, false); } } } } internal class RestedDelay { [HarmonyPatch(typeof(SE_Cozy), "Setup")] private class RestedDelay_Patch { private static float originalRestedDelay = -1f; private static readonly float newRestedDelay = 10f; private static void Postfix(SE_Cozy __instance) { if (originalRestedDelay == -1f) { originalRestedDelay = __instance.m_delay; log.Info($"Original rested delay saved: {originalRestedDelay}"); } if (ConfigManager.ShorterRestedDelayEnabled.Value) { if (__instance.m_delay != newRestedDelay) { __instance.m_delay = 10f; log.Info($"Rested delay set to {__instance.m_delay}"); } } else if (__instance.m_delay != originalRestedDelay) { __instance.m_delay = originalRestedDelay; log.Info($"Rested delay reverted to {__instance.m_delay}"); } else { log.Info($"Rested delay is at {__instance.m_delay}"); } } } private static readonly LogManager log = new LogManager("Rested Delay", LogManager.LogLevel.Warning); } internal class SailingCameraChanges { [HarmonyPatch(typeof(GameCamera), "GetCameraPosition")] private class GameCamera_Patch { private static void Postfix(GameCamera __instance, ref float dt, ref Vector3 pos, ref Quaternion rot) { //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_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) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { UpdateShipControlledState(); float num = UpdateCameraOffset(dt); pos += Vector3.up * num; } } } private static readonly LogManager log = new LogManager("Sailing Camera", LogManager.LogLevel.Warning); private static readonly Dictionary<string, float> shipOffsets = new Dictionary<string, float> { { "Raft", 2f }, { "Karve", 3f }, { "VikingShip", 4f }, { "VikingShip_Ashlands", 5f } }; private static bool moveCameraUp = false; private static float currentOffset = 0f; private static float targetOffset = 0f; private const float smoothSpeed = 2f; private static void UpdateShipControlledState() { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) { return; } if (!ConfigManager.CameraUpWhenSailingEnabled.Value) { moveCameraUp = false; targetOffset = 0f; return; } Ship controlledShip = Player.m_localPlayer.GetControlledShip(); if (!Object.op_Implicit((Object)(object)controlledShip)) { moveCameraUp = false; targetOffset = 0f; return; } string text = ((Object)((Component)controlledShip).gameObject).name.Replace("(Clone)", "").Trim(); if (!shipOffsets.TryGetValue(text, out var value)) { value = 0f; } if (!moveCameraUp || !Mathf.Approximately(targetOffset, value)) { log.Info($"Controlling {text}, offset set to {value:F1}"); } moveCameraUp = true; targetOffset = value; } private static float UpdateCameraOffset(float dt) { if (ConfigManager.CameraUpWhenSailingEnabled.Value) { currentOffset = Mathf.Lerp(currentOffset, targetOffset, dt * 2f); } else { currentOffset = Mathf.Lerp(currentOffset, 0f, dt * 2f); } return currentOffset; } } internal class WispRadiusChanges { [HarmonyPatch(typeof(Demister), "OnEnable")] private class BiggerWispRadius_Patch { private static void Postfix([NotNull] ref Demister __instance) { if ((!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated()) && ConfigManager.BiggerWispRadiusEnabled.Value) { log.Info("Wisplight end range set to 30"); __instance.m_forceField.endRange = 30f; } } } private static readonly LogManager log = new LogManager("Wisp Radius", LogManager.LogLevel.Warning); } } namespace MarsarahTweaks.Patches.Grind { internal class FoodDurationChanges { [HarmonyPatch(typeof(ObjectDB), "Awake")] private class FoodDurationChanges_Patch { private static void Postfix(ObjectDB __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)ZNet.instance == (Object)null)) { UpdateFoodDurations(__instance, wasModified: false); } } } private static readonly LogManager log = new LogManager("Food Durations", LogManager.LogLevel.Warning); private static readonly Dictionary<string, int> foodDurations = new Dictionary<string, int> { { "Raspberry", 15 }, { "Blueberries", 15 }, { "MushroomYellow", 15 }, { "QueensJam", 30 }, { "DeerStew", 30 }, { "MinceMeatSauce", 30 }, { "CarrotSoup", 30 }, { "BlackSoup", 30 }, { "ShocklateSmoothie", 30 }, { "Sausages", 30 }, { "TurnipStew", 30 }, { "OnionSoup", 30 }, { "WolfMeatSkewer", 30 }, { "Eyescream", 30 }, { "FishWraps", 30 }, { "Bread", 30 }, { "MisthareSupreme", 30 }, { "MushroomOmelette", 30 }, { "Salad", 30 }, { "YggdrasilPorridge", 30 }, { "MagicallyStuffedShroom", 30 }, { "CookedAsksvinMeat", 25 }, { "CookedVoltureMeat", 25 }, { "FierySvinstew", 30 }, { "MashedMeat", 30 }, { "SpicyMarmalade", 30 }, { "ScorchingMedley", 30 }, { "SizzlingBerryBroth", 30 }, { "SparklingShroomshake", 30 } }; private static readonly Dictionary<string, float> originalFoodDurations = new Dictionary<string, float>(); public static void UpdateFoodDurations(ObjectDB objDB, bool wasModified) { if ((Object)(object)objDB == (Object)null || objDB.m_items == null) { return; } bool value = ConfigManager.StandardizedFoodDurationsEnabled.Value; if (!value && (!wasModified || originalFoodDurations.Count == 0)) { return; } foreach (KeyValuePair<string, int> foodDuration in foodDurations) { string prefabName = foodDuration.Key; GameObject val = objDB.m_items.Find((GameObject item) => (Object)(object)item != (Object)null && ((Object)item).name == prefabName); if ((Object)(object)val == (Object)null) { continue; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null) { continue; } SharedData shared = component.m_itemData.m_shared; float value2; if (value) { if (!originalFoodDurations.ContainsKey(prefabName)) { originalFoodDurations[prefabName] = shared.m_foodBurnTime; } float num = (float)foodDuration.Value * 60f; if (shared.m_foodBurnTime < num) { log.Info($"Setting {prefabName} duration from {shared.m_foodBurnTime}s to {num}s"); shared.m_foodBurnTime = num; } } else if (originalFoodDurations.TryGetValue(prefabName, out value2) && shared.m_foodBurnTime != value2) { log.Info($"Restoring {prefabName} duration to {value2}s"); shared.m_foodBurnTime = value2; } } if (!value) { originalFoodDurations.Clear(); } } } internal class BuildPieceChanges { [HarmonyPatch(typeof(ZNetScene), "Awake")] private class BuildPiecesModifications_Patch { private static void Postfix(ref ZNetScene __instance) { if (!((Object)(object)__instance == (Object)null) && (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated()) && (ConfigManager.BuildPieceAmountsEnabled.Value || ConfigManager.BuildPieceMaterialsEnabled.Value)) { UpdateBuildPieces(__instance, amountsWasChanged: false, materialsWasChanged: false); } } } private static readonly LogManager log = new LogManager("Build Piece Changes", LogManager.LogLevel.Warning); private static readonly Dictionary<string, Dictionary<string, (string originalResItem, string newResItem, int amount)>> defaultBuildPieceRequirements = new Dictionary<string, Dictionary<string, (string, string, int)>>(); private static Dictionary<string, Dictionary<string, int>> newPieceAmounts = new Dictionary<string, Dictionary<string, int>> { { "$piece_rock_01", new Dictionary<string, int> { { "Stone", 8 } } }, { "$piece_rock_02", new Dictionary<string, int> { { "Stone", 5 } } }, { "$piece_woodfencegate", new Dictionary<string, int> { { "Wood", 2 } } }, { "$piece_stonefence", new Dictionary<string, int> { { "Stone", 3 } } }, { "$piece_birdnest", new Dictionary<string, int> { { "Acorn", 1 } } }, { "$piece_preptable", new Dictionary<string, int> { { "FineWood", 10 }, { "LeatherScraps", 10 } } }, { "$piece_cookingstation_iron", new Dictionary<string, int> { { "Iron", 2 }, { "Chain", 2 } } }, { "$piece_itemstand", new Dictionary<string, int> { { "FineWood", 2 } } }, { "$piece_blastfurnace", new Dictionary<string, int> { { "Iron", 5 } } }, { "$piece_oven", new Dictionary<string, int> { { "Iron", 5 } } }, { "$piece_forge_ext3", new Dictionary<string, int> { { "Wood", 15 } } }, { "$piece_forge_ext4", new Dictionary<string, int> { { "Iron", 7 } } }, { "$piece_forge_ext5", new Dictionary<string, int> { { "FineWood", 10 } } }, { "$piece_forge_ext6", new Dictionary<string, int> { { "Iron", 5 } } }, { "$piece_woodwindowshutter", new Dictionary<string, int> { { "Wood", 2 } } }, { "$piece_darkwoodgate", new Dictionary<string, int> { { "Iron", 3 } } }, { "$piece_irongate", new Dictionary<string, int> { { "Iron", 3 } } }, { "$piece_chest", new Dictionary<string, int> { { "Iron", 1 } } }, { "$piece_chestprivate", new Dictionary<string, int> { { "Iron", 4 } } }, { "$piece_chestblackmetal", new Dictionary<string, int> { { "BlackMetal", 4 } } }, { "$piece_brazierceiling01", new Dictionary<string, int> { { "Bronze", 3 } } }, { "$piece_sconce", new Dictionary<string, int> { { "Copper", 1 } } }, { "$piece_groundtorchwood", new Dictionary<string, int> { { "Wood", 1 } } }, { "$piece_groundtorch", new Dictionary<string, int> { { "Iron", 1 } } }, { "$piece_groundtorchgreen", new Dictionary<string, int> { { "Iron", 1 } } }, { "$piece_groundtorchblue", new Dictionary<string, int> { { "Iron", 1 } } }, { "$piece_portal", new Dictionary<string, int> { { "FineWood", 10 } } }, { "$piece_portal_stone", new Dictionary<string, int> { { "Grausten", 10 } } }, { "$piece_rug_lox", new Dictionary<string, int> { { "LoxPelt", 3 } } }, { "$piece_rug_wolf", new Dictionary<string, int> { { "WolfPelt", 3 } } }, { "$piece_rug_deer", new Dictionary<string, int> { { "DeerHide", 3 } } }, { "$piece_banner01", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner02", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner03", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner04", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner05", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner06", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner07", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner08", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner09", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner10", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner11", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner12", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner13", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_banner14", new Dictionary<string, int> { { "LeatherScraps", 5 } } }, { "$piece_fermenter", new Dictionary<string, int> { { "FineWood", 15 } } }, { "$piece_bathtub", new Dictionary<string, int> { { "Iron", 5 } } }, { "$piece_crystalwall1x1", new Dictionary<string, int> { { "Crystal", 1 } } }, { "$piece_incinerator", new Dictionary<string, int> { { "Iron", 5 } } }, { "$piece_stonewall1x1", new Dictionary<string, int> { { "Stone", 2 } } }, { "$piece_stonewall2x1", new Dictionary<string, int> { { "Stone", 3 } } }, { "$piece_stonepillar", new Dictionary<string, int> { { "Stone", 3 } } }, { "$piece_stonearch", new Dictionary<string, int> { { "Stone", 3 } } }, { "$piece_stonefloor2x2", new Dictionary<string, int> { { "Stone", 4 } } }, { "$piece_stonestair", new Dictionary<string, int> { { "Stone", 3 } } }, { "$piece_darkwoodraven", new Dictionary<string, int> { { "FineWood", 6 } } }, { "$piece_darkwoodwolf", new Dictionary<string, int> { { "FineWood", 6 } } }, { "$piece_blackmarble_throne", new Dictionary<string, int> { { "Copper", 4 } } }, { "$piece_blackmarble2x1x1", new Dictionary<string, int> { { "BlackMarble", 3 } } }, { "$piece_blackmarble_stair", new Dictionary<string, int> { { "BlackMarble", 3 } } }, { "$piece_blackmarble_base1", new Dictionary<string, int> { { "BlackMarble", 4 } } }, { "$piece_blackmarble_basecorner", new Dictionary<string, int> { { "BlackMarble", 5 } } }, { "$piece_blackmarble_out1", new Dictionary<string, int> { { "BlackMarble", 4 } } }, { "$piece_blackmarble_outcorner", new Dictionary<string, int> { { "BlackMarble", 5 } } }, { "$piece_blackmarble_arch", new Dictionary<string, int> { { "BlackMarble", 4 } } }, { "$piece_dvergr_stake_wall", new Dictionary<string, int> { { "YggdrasilWood", 4 }, { "Iron", 2 } } }, { "$piece_sharpstakes", new Dictionary<string, int> { { "Wood", 4 }, { "RoundLog", 2 } } }, { "$piece_dvergr_sharpstakes", new Dictionary<string, int> { { "YggdrasilWood", 4 }, { "Iron", 1 } } }, { "$piece_trap", new Dictionary<string, int> { { "BlackMetal", 3 }, { "BronzeNails", 5 } } }, { "$piece_turret", new Dictionary<string, int> { { "BlackMetal", 7 }, { "YggdrasilWood", 7 }, { "MechanicalSpring", 2 } } }, { "$piece_eitrrefinery", new Dictionary<string, int> { { "BlackMarble", 10 } } }, { "$piece_blackforge_ext2", new Dictionary<string, int> { { "Copper", 5 } } }, { "$piece_sapcollector", new Dictionary<string, int> { { "YggdrasilWood", 5 }, { "BlackMetal", 3 } } }, { "$piece_magetable", new Dictionary<string, int> { { "YggdrasilWood", 10 }, { "BlackMetal", 5 } } }, { "$piece_magetable_ext", new Dictionary<string, int> { { "BlackMarble", 5 }, { "Eitr", 5 } } }, { "$piece_magetable_ext2", new Dictionary<string, int> { { "BlackMarble", 5 }, { "Eitr", 5 } } }, { "$piece_magetable_ext3", new Dictionary<string, int> { { "Eitr", 5 } } }, { "$piece_hexagonalgate", new Dictionary<string, int> { { "Copper", 4 } } }, { "$piece_dvergr_spiralstair", new Dictionary<string, int> { { "YggdrasilWood", 3 }, { "Copper", 1 } } }, { "$piece_dvergr_spiralstair_right", new Dictionary<string, int> { { "YggdrasilWood", 3 }, { "Copper", 1 } } }, { "$piece_blackmarble_bench", new Dictionary<string, int> { { "BlackMarble", 5 }, { "Copper", 2 } } }, { "$piece_table_round", new Dictionary<string, int> { { "IronNails", 10 } } }, { "$piece_blackmarble_table", new Dictionary<string, int> { { "BlackMarble", 5 }, { "Copper", 2 } } }, { "$piece_brazierfloor01", new Dictionary<string, int> { { "Bronze", 3 } } }, { "$piece_brazierfloor02", new Dictionary<string, int> { { "Bronze", 3 }, { "GreydwarfEye", 2 } } }, { "$piece_jute_carpet", new Dictionary<string, int> { { "JuteRed", 3 } } }, { "$piece_juteblue_carpet", new Dictionary<string, int> { { "JuteBlue", 3 } } }, { "$piece_rug_hare", new Dictionary<string, int> { { "ScaleHide", 2 } } }, { "$piece_dvergr_lantern", new Dictionary<string, int> { { "Copper", 1 } } }, { "$piece_dvergr_lantern_pole", new Dictionary<string, int> { { "Copper", 2 } } }, { "$piece_clothdoor", new Dictionary<string, int> { { "JuteRed", 3 } } }, { "$piece_hanging_cloth_blue1", new Dictionary<string, int> { { "JuteBlue", 3 } } }, { "$piece_hanging_cloth_blue2", new Dictionary<string, int> { { "JuteBlue", 3 } } }, { "$piece_ashwood_archedwall", new Dictionary<string, int> { { "Blackwood", 1 } } }, { "$piece_ashwood_floor_deco", new Dictionary<string, int> { { "Blackwood", 2 } } }, { "$piece_ashwoodstair", new Dictionary<string, int> { { "Blackwood", 1 } } }, { "$piece_ashwood_decowall", new Dictionary<string, int> { { "Blackwood", 2 } } }, { "$piece_ashwood_decowall_divider", new Dictionary<string, int> { { "Blackwood", 1 } } }, { "$piece_ashwood_decowall_tree", new Dictionary<string, int> { { "Blackwood", 1 } } }, { "$piece_grausten_stoneladder", new Dictionary<string, int> { { "Grausten", 3 } } }, { "$piece_grausten_stair", new Dictionary<string, int> { { "Grausten", 3 } } }, { "$piece_grausten_floor1x1", new Dictionary<string, int> { { "Grausten", 1 } } }, { "$piece_grausten_pillarmedium", new Dictionary<string, int> { { "Grausten", 2 } } }, { "$piece_grausten_pillartapered", new Dictionary<string, int> { { "Grausten", 4 } } }, { "$piece_grausten_pillartaperedinverted", new Dictionary<string, int> { { "Grausten", 4 } } }, { "$piece_grausten_beammedium", new Dictionary<string, int> { { "Grausten", 2 } } }, { "$piece_grausten_wall1x2", new Dictionary<string, int> { { "Grausten", 2 } } }, { "$piece_grausten_wall2x2", new Dictionary<string, int> { { "Grausten", 4 } } }, { "$piece_grausten_wall4x2", new Dictionary<string, int> { { "Grausten", 8 } } }, { "$piece_grausten_window4x2", new Dictionary<string, int> { { "Grausten", 8 } } }, { "$piece_grausten_roof45_corner", new Dictionary<string, int> { { "Grausten", 4 } } }, { "$piece_grausten_roof45_corner2", new Dictionary<string, int> { { "Grausten", 4 } } }, { "$piece_grausten_roof45_archcorner", new Dictionary<string, int> { { "Grausten", 4 } } }, { "$piece_grausten_roof45_archcorner2", new Dictionary<string, int> { { "Grausten", 4 } } }, { "$piece_flametalgate", new Dictionary<string, int> { { "FlametalNew", 8 } } }, { "$piece_rug_asksvin", new Dictionary<string, int> { { "AskHide", 3 } } } }; private static Dictionary<string, Dictionary<string, string>> newPieceMaterials = new Dictionary<string, Dictionary<string, string>> { { "$piece_workbench_ext4", new Dictionary<string, string> { { "Obsidian", "Coal" } } }, { "$piece_darkwoodgate", new Dictionary<string, string> { { "Iron", "BlackMetal" } } }, { "$piece_bathtub", new Dictionary<string, string> { { "Iron", "BlackMetal" } } } }; public static void UpdateBuildPieces(ZNetScene znScene, bool amountsWasChanged, bool materialsWasChanged) { foreach (GameObject prefab in znScene.m_prefabs) { Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { continue; } Requirement[] resources = component.m_resources; string name = component.m_name; bool flag = ConfigManager.BuildPieceAmountsEnabled.Value && newPieceAmounts.ContainsKey(name); bool flag2 = ConfigManager.BuildPieceMaterialsEnabled.Value && newPieceMaterials.ContainsKey(name); Requirement[] array = resources; foreach (Requirement val in array) { if (flag && newPieceAmounts[name].TryGetValue(((Object)val.m_resItem).name, out var value)) { CreateBackup(name, val, null); log.Info($"(Piece Amounts) Applying amounts for Piece {name} - Resource {((Object)val.m_resItem).name}: {val.m_amount} -> {value}"); ApplyChanges(val, (newResItem: null, amount: value)); } if (flag2 && newPieceMaterials[name].TryGetValue(((Object)val.m_resItem).name, out var value2)) { CreateBackup(name, val, value2); log.Info("(Piece Materials) Applying material for Piece " + name + " - Resource " + ((Object)val.m_resItem).name + " -> " + value2); ApplyChanges(val, (newResItem: value2, amount: null), modifyResItem: true); } if (!ConfigManager.BuildPieceAmountsEnabled.Value && newPieceAmounts.ContainsKey(name) && amountsWasChanged) { log.Info($"(Gear Amounts) Was changed: {amountsWasChanged}"); if (RestoreBackup(name, val, restoreMaterials: false) && (!flag2 || !newPieceMaterials[name].ContainsKey(((Object)val.m_resItem).name))) { log.Info("(Piece Amounts) Removing backup for: " + name + " - " + ((Object)val.m_resItem).name); defaultBuildPieceRequirements[name].Remove(((Object)val.m_resItem).name); } } if (!(!ConfigManager.BuildPieceMaterialsEnabled.Value && newPieceMaterials.ContainsKey(name) && materialsWasChanged)) { continue; } log.Info($"(Gear Materials) Was changed: {materialsWasChanged}"); if (!RestoreBackup(name, val, restoreMaterials: true)) { continue; } if (flag && newPieceAmounts[name].ContainsKey(((Object)val.m_resItem).name)) { if (newPieceAmounts[name].TryGetValue(((Object)val.m_resItem).name, out var value3)) { log.Info("(Piece Materials - Amounts) Re-applying changes for: " + name + " - " + ((Object)val.m_resItem).name); ApplyChanges(val, (newResItem: null, amount: value3)); } } else if (!flag || !newPieceAmounts[name].ContainsKey(((Object)val.m_resItem).name)) { log.Info("(Piece Materials) Removing backup for: " + name + " - " + ((Object)val.m_resItem).name); defaultBuildPieceRequirements[name].Remove(((Object)val.m_resItem).name); } } if (defaultBuildPieceRequirements.ContainsKey(name) && defaultBuildPieceRequirements[name].Count == 0) { log.Info("(Cleanup) Removing backup for: " + name); defaultBuildPieceRequirements.Remove(name); } } } private static void ApplyChanges(Requirement req, (string newResItem, int? amount) values, bool modifyResItem = false) { if (values.amount.HasValue && req.m_amount != values.amount.Value) { log.Info($"Applying amounts for Resource {((Object)req.m_resItem).name}: {req.m_amount} -> {values.amount.Value}"); req.m_amount = values.amount.Value; } if (modifyResItem && !string.IsNullOrEmpty(values.newResItem) && ((Object)req.m_resItem).name != values.newResItem) { log.Info("Applying material for Resource " + ((Object)req.m_resItem).name + " -> " + values.newResItem); req.m_resItem = ZNetScene.instance.GetPrefab(values.newResItem).GetComponent<ItemDrop>(); } } private static void CreateBackup(string pieceName, Requirement req, string newResItem) { if (!defaultBuildPieceRequirements.TryGetValue(pieceName, out Dictionary<string, (string, string, int)> value)) { value = new Dictionary<string, (string, string, int)>(); defaultBuildPieceRequirements[pieceName] = value; } string name = ((Object)req.m_resItem).name; if (value.TryGetValue(name, out var value2)) { if (newResItem != null && value2.Item2 == null) { log.Info("Updating backup for " + pieceName + " - oldResItem: " + name + " with newResItem: " + newResItem); value[name] = (value2.Item1, newResItem, value2.Item3); } } else { log.Info("Creating new backup for " + pieceName + " - " + name); value[name] = (name, newResItem, req.m_amount); } } private static bool RestoreBackup(string pieceName, Requirement req, bool restoreMaterials) { if (!defaultBuildPieceRequirements.TryGetValue(pieceName, out Dictionary<string, (string, string, int)> value)) { log.Info("Restore backup first check."); return false; } log.Info("Restore backup - Recipe name: " + pieceName + ", Given requirement: " + ((Object)req.m_resItem).name); foreach (KeyValuePair<string, (string, string, int)> item in value) { var (text, text2, num) = item.Value; log.Info($"Restore backup - values: {text}, {text2}, {restoreMaterials}"); if (((Object)req.m_resItem).name == text2 && restoreMaterials) { log.Info("Restoring original material for " + pieceName + " from " + ((Object)req.m_resItem).name + " to " + text); req.m_resItem = ZNetScene.instance.GetPrefab(text).GetComponent<ItemDrop>(); break; } } if (value.TryGetValue(((Object)req.m_resItem).name, out var value2)) { log.Info("Restoring backup for: " + pieceName + " - " + ((Object)req.m_resItem).name); req.m_amount = value2.Item3; return true; } log.Info("Restore backup - we got to the end."); return false; } public static void LogBuildPieces(ZNetScene znScene) { if ((Object)(object)znScene == (Object)null) { log.Warn("ZNetScene is null. Cannot log build pieces."); return; } log.Info("=== Logging All Build Pieces ==="); foreach (GameObject prefab in znScene.m_prefabs) { Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { continue; } log.Info("[Piece] Name: " + component.m_name + ", Prefab: " + ((Object)prefab).name); if (component.m_resources != null && component.m_resources.Length != 0) { Requirement[] resources = component.m_resources; foreach (Requirement val in resources) { if (!((Object)(object)val?.m_resItem == (Object)null)) { log.Info($" - Resource: {((Object)val.m_resItem).name}, Amount: {val.m_amount}"); } } } else { log.Info(" (No build requirements)"); } } log.Info("=== Finished Logging Build Pieces ==="); } public static void LogBuildPiecesExtra(ZNetScene znScene) { if ((Object)(object)znScene == (Object)null) { log.Warn("ZNetScene is null. Cannot log build pieces."); return; } log.Info("=== Build Piece Costs ==="); foreach (GameObject prefab in znScene.m_prefabs) { Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component == (Object)null || component.m_resources == null || component.m_resources.Length == 0) { continue; } Dictionary<string, int> value; bool flag = newPieceAmounts.TryGetValue(component.m_name, out value); log.Info("[Piece] " + component.m_name + " | Prefab: " + ((Object)prefab).name); Requirement[] resources = component.m_resources; foreach (Requirement val in resources) { if (!((Object)(object)val?.m_resItem == (Object)null)) { int amount = val.m_amount; if (flag && value.TryGetValue(((Object)val.m_resItem).name, out var value2) && value2 != amount) { log.Info($" - {((Object)val.m_resItem).name}: Vanilla {amount} -> Modified {value2}"); } else { log.Info($" - {((Object)val.m_resItem).name}: Vanilla {amount}"); } } } } log.Info("=== End Build Piece Costs ==="); } private static void LogPrefabs(ZNetScene znScene) { if ((Object)(object)znScene == (Object)null) { log.Warn("ZNetScene is null, cannot log prefabs."); return; } log.Info("=== Listing all Prefabs in ZNetScene ==="); foreach (GameObject prefab in znScene.m_prefabs) { if (!((Object)(object)prefab == (Object)null)) { string name = ((Object)prefab).name; Piece component = prefab.GetComponent<Piece>(); ItemDrop component2 = prefab.GetComponent<ItemDrop>(); Character component3 = prefab.GetComponent<Character>(); string text = "Generic GameObject"; if ((Object)(object)component != (Object)null) { text = "Build Piece"; } else if ((Object)(object)component2 != (Object)null) { text = "Item"; } else if ((Object)(object)component3 != (Object)null) { text = "Character"; } log.Info("Prefab: " + name + " (" + text + ")"); } } log.Info("=== End of Prefabs List ==="); } } internal class DoubleBronzeCrafting { [HarmonyPatch(typeof(ObjectDB), "Awake")] private class OthersSection_Patch { private static void Postfix(ref ObjectDB __instance) { if (!((Object)(object)__instance == (Object)null) && (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated())) { UpdateDoubleBronzeCrafting(__instance, wasChanged: false); } } } private static readonly LogManager log = new LogManager("Double Bronze", LogManager.LogLevel.Warning); private static readonly Dictionary<string, int> doubleBronzeOriginals = new Dictionary<string, int>(); private static readonly Dictionary<string, int> doubleBronzeChanges = new Dictionary<string, int> { { "Recipe_Bronze", 2 }, { "Recipe_Bronze5", 10 } }; public static void UpdateDoubleBronzeCrafting(ObjectDB objDB, bool wasChanged) { if (ConfigManager.DoubleBronzeEnabled.Value) { foreach (string recipeName in doubleBronzeChanges.Keys) { Recipe val = objDB.m_recipes.Find((Recipe r) => ((Object)r).name == recipeName); if (!((Object)(object)val == (Object)null)) { if (!doubleBronzeOriginals.ContainsKey(((Object)val).name)) { doubleBronzeOriginals[((Object)val).name] = val.m_amount; log.Info("Backed up " + ((Object)val).name); } val.m_amount = doubleBronzeChanges[((Object)val).name]; log.Info("Applied new values for " + ((Object)val).name); } } return; } if (!wasChanged) { return; } foreach (string recipeName2 in doubleBronzeOriginals.Keys) { Recipe val2 = objDB.m_recipes.Find((Recipe r) => ((Object)r).name == recipeName2); if (!((Object)(object)val2 == (Object)null)) { val2.m_amount = doubleBronzeOriginals[((Object)val2).name]; log.Info("Restored " + ((Object)val2).name); } } doubleBronzeOriginals.Clear(); } } internal class FoodAndMeadChanges { [HarmonyPatch(typeof(ObjectDB), "Awake")] private class FoodAndMeadChanges_Patch { private static void Postfix(ref ObjectDB __instance) { if (!((Object)(object)__instance == (Object)null)) { UpdateFoodAndMead(__instance, wasModified: false); } } } private class RecipeModification { public Dictionary<string, int> ResourceChanges { get; set; } = new Dictionary<string, int>(); public Dictionary<string, string> ResourceReplacements { get; set; } = new Dictionary<string, string>(); public Dictionary<string, (string originalResItem, string newResItem)> OriginalResourceReplacements { get; set; } = new Dictionary<string, (string, string)>(); public int? RecipeAmount { get; set; } } private class FoodStatModification { public float? Health { get; set; } public float? Stamina { get; set; } public float? Eitr { get; set; } public float? Regen { get; set; } } private static readonly LogManager log = new LogManager("Food And Mead", LogManager.LogLevel.Warning); private static Dictionary<string, RecipeModification> foodRecipeModifications = new Dictionary<string, RecipeModification> { { "Recipe_QueensJam", new RecipeModification { ResourceChanges = { { "Raspberry", 5 }, { "Blueberries", 5 } } } }, { "Recipe_TurnipStew", new RecipeModification { RecipeAmount = 2 } }, { "Recipe_Blacksoup", new RecipeModification { ResourceChanges = { { "Bloodbag", 2 }, { "Honey", 2 }, { "Turnip", 2 } }, RecipeAmount = 2 } }, { "Recipe_CarrotSoup", new RecipeModification { RecipeAmount = 2 } }, { "Recipe_DeerStew", new RecipeModification { ResourceChanges = { { "CookedDeerMeat", 2 }, { "Blueberries", 2 }, { "Carrot", 2 } }, RecipeAmount = 2 } }, { "Recipe_ShocklateSmoothie", new RecipeModification { RecipeAmount = 2 } }, { "Recipe_MinceMeatSauce", new RecipeModification { ResourceChanges = { { "RawMeat", 2 }, { "NeckTail", 2 }, { "Carrot", 2 } }, RecipeAmount = 2 } }, { "Recipe_Eyescream", new RecipeModification { RecipeAmount = 2 } }, { "Recipe_PulledBear", new RecipeModification { ResourceChanges = { { "CookedBjornMeat", 2 }, { "Blueberries", 2 } }, RecipeAmount = 2 } }, { "Recipe_Onionsoup", new RecipeModification { RecipeAmount = 2 } }, { "Recipe_WolfSkewer", new RecipeModification { ResourceChanges = { { "WolfMeat", 2 }, { "Onion", 2 } }, RecipeAmount = 2 } }, { "Recipe_SerpentStew", new RecipeModification { ResourceChanges = { { "Mushroom", 2 }, { "SerpentMeatCooked", 2 } }, RecipeAmount = 2 } }, { "Recipe_BloodPudding", new RecipeModification { RecipeAmount = 2 } }, { "Recipe_FishWraps", new RecipeModification { RecipeAmount = 2 } }, { "Recipe_FishAndBread", new RecipeModification { RecipeAmount = 2 } }, { "Recipe_LoxPie", new RecipeModification { RecipeAmount = 2 } }, { "Recipe_Bread", new RecipeModification { ResourceChanges = { { "BarleyFlour", 6 } } } }, { "Recipe_HoneyGlazedChicken", new RecipeModification { ResourceChanges = { { "ChickenMeat", 2 } }, RecipeAmount = 2 } }, { "Recipe_MagicallyStuffedShroom", new RecipeModification { ResourceChanges = { { "GiantBloodSack", 2 } }, RecipeAmount = 2 } }, { "Recipe_MeatPlatter", new RecipeModification { ResourceChanges = { { "BugMeat", 2 }, { "LoxMeat", 2 }, { "HareMeat", 2 } }, RecipeAmount = 2 } }, { "Recipe_MisthareSupreme", new RecipeModification { ResourceChanges = { { "HareMeat", 2 } }, RecipeAmount = 2 } }, { "Recipe_MushroomOmelette", new RecipeModification { ResourceChanges = { { "ChickenEgg", 2 } }, RecipeAmount = 2 } }, { "Recipe_Salad", new RecipeModification { ResourceChanges = { { "MushroomJotunPuffs", 4 }, { "Onion", 4 }, { "Cloudberry", 4 } }, RecipeAmount = 4 } }, { "Recipe_YggdrasilPorridge", new RecipeModification { ResourceChanges = { { "Sap", 2 }, { "Barley", 2 } }, RecipeAmount = 2 } }, { "Recipe_FierySvinstew", new RecipeModification { ResourceChanges = { { "AsksvinMeat", 2 }, { "MushroomSmokePuff", 2 } }, RecipeAmount = 2 } }, { "Recipe_MarinatedGreens", new RecipeModification { ResourceChanges = { { "Sap", 2 } }, RecipeAmount = 2 } }, { "Recipe_SizzlingBerryBroth", new RecipeModification { ResourceChanges = { { "Sap", 2 } }, RecipeAmount = 2 } }, { "Recipe_SparklingShroomshake", new RecipeModification { ResourceChanges = { { "Sap", 2 } }, RecipeAmount = 2 } }, { "Recipe_MashedMeat", new RecipeModification { ResourceChanges = { { "AsksvinMeat", 2 }, { "VoltureMeat", 2 }, { "Fiddleheadfern", 2 } }, RecipeAmount = 2 } }, { "Recipe_ScorchingMedley", new RecipeModification { ResourceChanges = { { "MushroomJotunPuffs", 4 }, { "Onion", 4 }, { "Fiddleheadfern", 4 } }, RecipeAmount = 4 } }, { "Recipe_SpiceInducedMarmalade", new RecipeModification { ResourceChanges = { { "Vineberry", 2 }, { "Honey", 2 }, { "Fiddleheadfern", 2 } }, RecipeAmount = 2 } }, { "Recipe_RoastedCrustPie", new RecipeModification { ResourceChanges = { { "VoltureEgg", 2 } }, RecipeAmount = 2 } }, { "Recipe_PiquantPie", new RecipeModification { RecipeAmount = 2 } } }; private static Dictionary<string, RecipeModification> meadAndWineModifications = new Dictionary<string, RecipeModification> { { "Recipe_MeadBaseEitrLingering", new RecipeModification { ResourceChanges = { { "Sap", 5 }, { "Vineberry", 5 }, { "MushroomMagecap", 5 } } } }, { "Recipe_MeadBaseHealthLingering", new RecipeModification { ResourceChanges = { { "Sap", 5 }, { "Vineberry", 5 }, { "MushroomSmokePuff", 5 } } } }, { "Recipe_BarleyWineBase", new RecipeModification { ResourceChanges = { { "Barley", 5 }, { "Cloudberry", 5 } } } }, { "Recipe_MeadBaseEitrMinor", new RecipeModification { ResourceChanges = { { "Honey", 5 }, { "Sap", 3 }, { "MushroomMagecap", 3 } } } }, { "Recipe_MeadBaseFrostResist", new RecipeModification { ResourceChanges = { { "Honey", 5 }, { "Thistle", 3 } } } }, { "Recipe_MeadBaseHealthMajor", new RecipeModification { ResourceChanges = { { "Honey", 5 }, { "GiantBloodSack", 2 }, { "RoyalJelly", 3 } }, ResourceReplacements = { { "RoyalJelly", "MushroomJotunPuffs" } } } }, { "Recipe_MeadBaseHealthMedium", new RecipeModification { ResourceChanges = { { "Honey", 5 }, { "Bloodbag", 3 }, { "Raspberry", 5 } } } }, { "Recipe_MeadBaseHealthMinor", new RecipeModification { ResourceChanges = { { "Honey", 5 }, { "Raspberry", 5 } } } }, { "Recipe_MeadBasePoisonResist", new RecipeModification { ResourceChanges = { { "Honey", 5 }, { "Thistle", 3 }, { "Coal", 5 } } } }, { "Recipe_MeadBaseStaminaLingering", new RecipeModification { ResourceChanges = { { "Sap", 5 }, { "Cloudberry", 5 }, { "MushroomJotunPuffs", 5 } } } }, { "Recipe_MeadBaseStaminaMedium", new RecipeModification { ResourceChanges = { { "Honey", 5 }, { "Cloudberry", 5 } } } }, { "Recipe_MeadBaseStaminaMinor", new RecipeModification { ResourceChanges = { { "Honey", 5 }, { "Raspberry", 5 } } } }, { "Recipe_MeadBaseTasty", new RecipeModification { ResourceChanges = { { "Honey", 5 }, { "Raspberry", 5 } } } }, { "Recipe_MeadBaseHasty", new RecipeModification { ResourceChanges = { { "Honey", 5 }, { "Blueberries", 5 } } } }, { "Recipe_MeadBaseStrength", new RecipeModification { ResourceChanges = { { "Honey", 5 } } } }, { "Recipe_MeadBaseSwimmer", new RecipeModification { ResourceChanges = { { "Dandelion", 7 } } } }, { "Recipe_MeadBaseTamer", new RecipeModification { ResourceChanges = { { "Carrot", 5 } } } }, { "Recipe_MeadBaseBzerker", new RecipeModification { ResourceChanges = { { "Mushroom", 5 }, { "MushroomYellow", 5 } } } } }; private static Dictionary<string, int> foodStacksModifications = new Dictionary<string, int> { { "QueensJam", 20 }, { "CarrotSoup", 20 }, { "DeerStew", 20 }, { "TurnipStew", 20 }, { "PulledBear", 20 }, { "BlackSoup", 20 }, { "Eyescream", 20 }, { "ShocklateSmoothie", 20 }, { "MinceMeatSauce", 20 }, { "OnionSoup", 20 }, { "SerpentStew", 20 }, { "BloodPudding", 20 }, { "FishWraps", 20 }, { "FishAndBread", 20 }, { "LoxPie", 20 }, { "MushroomOmelette", 20 }, { "YggdrasilPorridge", 20 }, { "CookedEgg", 20 }, { "Salad", 20 }, { "SeekerAspic", 20 }, { "HoneyGlazedChicken", 20 }, { "MagicallyStuffedShroom", 20 }, { "MeatPlatter", 20 }, { "MisthareSupreme", 20 }, { "FierySvinstew", 20 }, { "MarinatedGreens", 20 }, { "MashedMeat", 20 }, { "ScorchingMedley", 20 }, { "SizzlingBerryBroth", 20 }, { "SpicyMarmalade", 20 }, { "SparklingShroomshake", 20 }, { "RoastedCrustPie", 20 }, { "PiquantPie", 20 }, { "FishAndBreadUncooked", 20 }, { "LoxPieUncooked", 20 }, { "HoneyGlazedChickenUncooked", 20 }, { "MagicallyStuffedShroomUncooked", 20 }, { "MeatPlatterUncooked", 20 }, { "MisthareSupremeUncooked", 20 }, { "RoastedCrustPieUncooked", 20 }, { "PiquantPieUncooked", 20 } }; private static readonly Dictionary<string, FoodStatModification> foodStatModifications = new Dictionary<string, FoodStatModification> { { "PulledBear", new FoodStatModification { Health = 45f } } }; private static Dictionary<string, RecipeModification> recipeModifications; private static Dictionary<string, RecipeModification> originalRecipeValues = new Dictionary<string, RecipeModification>(); private static Dictionary<string, int> originalFoodStacks = new Dictionary<string, int>(); private static readonly Dictionary<string, FoodStatModification> originalFoodStats = new Dictionary<string, FoodStatModification>(); private static Dictionary<string, RecipeModification> GetRecipeModifications() { if (recipeModifications == null) { recipeModifications = foodRecipeModifications; foreach (KeyValuePair<string, RecipeModification> meadAndWineModification in meadAndWineModifications) { recipeModifications[meadAndWineModification.Key] = meadAndWineModification.Value; } } return recipeModifications; } public static void UpdateFoodAndMead(ObjectDB objDB, bool wasModified) { Dictionary<string, RecipeModification> dictionary = GetRecipeModifications(); if (ConfigManager.FoodAndMeadModificationsEnabled.Value) { foreach (KeyValuePair<string, RecipeModification> item in dictionary) { string recipeName = item.Key; RecipeModification value = item.Value; Recipe val = ((IEnumerable<Recipe>)objDB.m_recipes).FirstOrDefault((Func<Recipe, bool>)((Recipe r) => (