Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Plantations v1.0.0
plugins/Plantations.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.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using ItemManager; using JetBrains.Annotations; using LocalizationManager; using Microsoft.CodeAnalysis; using PieceManager; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: Guid("E74EB49A-461D-48EA-85BC-F462D60C98C4")] [assembly: ComVisible(false)] [assembly: AssemblyTrademark("")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyProduct("Plantations")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyDescription("")] [assembly: AssemblyTitle("Plantations")] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyFileVersion("1.0.0")] [assembly: AssemblyCompany("Radamanto")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: <54ca3906-ef3e-46f6-b77a-2e89598568e3>RefSafetyRules(11)] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [<815be31a-154e-4472-a809-be812271944a>Embedded] internal sealed class <815be31a-154e-4472-a809-be812271944a>EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [<815be31a-154e-4472-a809-be812271944a>Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class <f3227ed5-460d-44c0-9306-fa369a7eaa99>NullableAttribute : Attribute { public readonly byte[] NullableFlags; public <f3227ed5-460d-44c0-9306-fa369a7eaa99>NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public <f3227ed5-460d-44c0-9306-fa369a7eaa99>NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [<815be31a-154e-4472-a809-be812271944a>Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class <c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContextAttribute : Attribute { public readonly byte Flag; public <c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContextAttribute(byte P_0) { Flag = P_0; } } [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] [<815be31a-154e-4472-a809-be812271944a>Embedded] [CompilerGenerated] internal sealed class <54ca3906-ef3e-46f6-b77a-2e89598568e3>RefSafetyRulesAttribute : Attribute { public readonly int Version; public <54ca3906-ef3e-46f6-b77a-2e89598568e3>RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LocalizationManager { [PublicAPI] [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)] [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] public class Localizer { private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors; private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts; private static readonly ConditionalWeakTable<Localization, string> localizationLanguage; private static readonly List<WeakReference<Localization>> localizationObjects; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] private static BaseUnityPlugin _plugin; private static readonly List<string> fileExtensions; private static BaseUnityPlugin plugin { get { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown if (_plugin == null) { IEnumerable<TypeInfo> source; try { source = Assembly.GetExecutingAssembly().DefinedTypes.ToList(); } catch (ReflectionTypeLoadException ex) { source = from t in ex.Types where t != null select t.GetTypeInfo(); } _plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); } return _plugin; } } [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] [method: <c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(2)] [field: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] public static event Action OnLocalizationComplete; private static void UpdatePlaceholderText(Localization localization, string key) { localizationLanguage.TryGetValue(localization, out var value); string text = loadedTexts[value][key]; if (PlaceholderProcessors.TryGetValue(key, out var value2)) { text = value2.Aggregate(text, [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (string current, KeyValuePair<string, Func<string>> kv) => current.Replace("{" + kv.Key + "}", kv.Value())); } localization.AddWord(key, text); } public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(new byte[] { 2, 1, 1 })] Func<T, string> convertConfigValue = null) { if (convertConfigValue == null) { convertConfigValue = (T val) => val.ToString(); } if (!PlaceholderProcessors.ContainsKey(key)) { PlaceholderProcessors[key] = new Dictionary<string, Func<string>>(); } config.SettingChanged += [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (object _, EventArgs _) => { UpdatePlaceholder(); }; if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage())) { UpdatePlaceholder(); } void UpdatePlaceholder() { PlaceholderProcessors[key][placeholder] = () => convertConfigValue(config.Value); UpdatePlaceholderText(Localization.instance, key); } } public static void AddText(string key, string text) { List<WeakReference<Localization>> list = new List<WeakReference<Localization>>(); foreach (WeakReference<Localization> localizationObject in localizationObjects) { if (localizationObject.TryGetTarget(out var target)) { Dictionary<string, string> dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)]; if (!target.m_translations.ContainsKey(key)) { dictionary[key] = text; target.AddWord(key, text); } } else { list.Add(localizationObject); } } foreach (WeakReference<Localization> item in list) { localizationObjects.Remove(item); } } public static void Load() { _ = plugin; } public static void LoadLocalizationLater(Localization __instance) { LoadLocalization(Localization.instance, __instance.GetSelectedLanguage()); } public static void SafeCallLocalizeComplete() { Localizer.OnLocalizationComplete?.Invoke(); } private static void LoadLocalization(Localization __instance, string language) { if (!localizationLanguage.Remove(__instance)) { localizationObjects.Add(new WeakReference<Localization>(__instance)); } localizationLanguage.Add(__instance, language); Dictionary<string, string> dictionary = new Dictionary<string, string>(); foreach (string item in from f in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories) where fileExtensions.IndexOf(Path.GetExtension(f)) >= 0 select f) { string[] array = Path.GetFileNameWithoutExtension(item).Split(new char[1] { '.' }); if (array.Length >= 2) { string text = array[1]; if (dictionary.ContainsKey(text)) { Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped.")); } else { dictionary[text] = item; } } } byte[] array2 = LoadTranslationFromAssembly("English"); if (array2 == null) { throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json or translations/English.yml."); } string input = Encoding.UTF8.GetString(array2).TrimStart(new char[1] { '\ufeff' }); Dictionary<string, string> dictionary2 = new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(input); if (dictionary2 == null) { throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty."); } string text2 = null; if (language != "English") { if (dictionary.TryGetValue(language, out var value)) { text2 = File.ReadAllText(value); } else { byte[] array3 = LoadTranslationFromAssembly(language); if (array3 != null) { text2 = Encoding.UTF8.GetString(array3); } } } if (text2 == null && dictionary.TryGetValue("English", out var value2)) { text2 = File.ReadAllText(value2); } if (text2 != null) { text2 = text2.TrimStart(new char[1] { '\ufeff' }); foreach (KeyValuePair<string, string> item2 in new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>()) { dictionary2[item2.Key] = item2.Value; } } loadedTexts[language] = dictionary2; foreach (KeyValuePair<string, string> item3 in dictionary2) { UpdatePlaceholderText(__instance, item3.Key); } } static Localizer() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Expected O, but got Unknown PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>(); loadedTexts = new Dictionary<string, Dictionary<string, string>>(); localizationLanguage = new ConditionalWeakTable<Localization, string>(); localizationObjects = new List<WeakReference<Localization>>(); fileExtensions = new List<string>(2) { ".json", ".yml" }; Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager"); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "SetupGui", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalizationLater", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "SafeCallLocalizeComplete", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } [return: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] private static byte[] LoadTranslationFromAssembly(string language) { foreach (string fileExtension in fileExtensions) { byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension); if (array != null) { return array; } } return null; } [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(2)] public static byte[] ReadEmbeddedFileBytes([<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(1)] string resourceFileName, Assembly containingAssembly = null) { using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal)); if (text != null) { containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream); } return (memoryStream.Length == 0L) ? null : memoryStream.ToArray(); } } public static class LocalizationManagerVersion { [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(1)] public const string Version = "1.4.1"; } } namespace Plantations { [HarmonyPatch] internal static class Code_PlantationsCultivatorRemoveOnly { private const string CultivatorPrefabName = "Cultivator"; private const string CloneSuffix = "(Clone)"; private const float RemoveWindow = 0.2f; private const float RemoveRayDistance = 50f; private const float TerrainModifierSearchRange = 2.5f; private static readonly HashSet<int> AllowedPieceHashes = new HashSet<int> { StringExtensionMethods.GetStableHashCode("RD_Dandelion"), StringExtensionMethods.GetStableHashCode("RD_Mushroom"), StringExtensionMethods.GetStableHashCode("RD_Mushroom_yellow"), StringExtensionMethods.GetStableHashCode("RD_RaspberryBush"), StringExtensionMethods.GetStableHashCode("RD_BlueberryBush"), StringExtensionMethods.GetStableHashCode("RD_thistle"), StringExtensionMethods.GetStableHashCode("RD_CloudberryBush"), StringExtensionMethods.GetStableHashCode("RD_MushroomSmokePuff"), StringExtensionMethods.GetStableHashCode("RD_Fiddlehead") }; private static readonly Dictionary<string, int> NameHashCache = new Dictionary<string, int>(32); private static readonly FieldRef<Player, float> RemovePressedTimeRef = AccessTools.FieldRefAccess<Player, float>("m_removePressedTime"); private static readonly FieldRef<Player, float> LastToolUseTimeRef = AccessTools.FieldRefAccess<Player, float>("m_lastToolUseTime"); private static readonly FieldRef<Player, float> RemoveDelayRef = AccessTools.FieldRefAccess<Player, float>("m_removeDelay"); private static readonly FieldRef<Player, int> BuildRemoveDebtRef = AccessTools.FieldRefAccess<Player, int>("m_buildRemoveDebt"); private static readonly Func<Player, bool> RemovePieceMethod = AccessTools.MethodDelegate<Func<Player, bool>>(AccessTools.DeclaredMethod(typeof(Player), "RemovePiece", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<Player, float> GetBuildStaminaMethod = AccessTools.MethodDelegate<Func<Player, float>>(AccessTools.DeclaredMethod(typeof(Player), "GetBuildStamina", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<Player, ItemData, float> GetPlaceDurabilityMethod = AccessTools.MethodDelegate<Func<Player, ItemData, float>>(AccessTools.DeclaredMethod(typeof(Player), "GetPlaceDurability", (Type[])null, (Type[])null), (object)null, true); private static int GetPrefabNameStableHash(string name) { if (string.IsNullOrEmpty(name)) { return 0; } if (NameHashCache.TryGetValue(name, out var value)) { return value; } string text = (name.EndsWith("(Clone)", StringComparison.Ordinal) ? name.Substring(0, name.Length - "(Clone)".Length) : name); value = StringExtensionMethods.GetStableHashCode(text); NameHashCache[name] = value; return value; } private static bool IsTrackedPlantPiece(Piece piece) { if (!Object.op_Implicit((Object)(object)piece)) { return false; } return AllowedPieceHashes.Contains(GetPrefabNameStableHash(((Object)((Component)piece).gameObject).name)); } private static bool IsCultivator(ItemData item) { if (item == null || (Object)(object)item.m_dropPrefab == (Object)null) { return false; } return Utils.GetPrefabName(item.m_dropPrefab) == "Cultivator"; } private static bool TryGetRemoveTarget(Player player, out Piece piece) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) piece = null; if ((Object)(object)player == (Object)null || (Object)(object)GameCamera.instance == (Object)null || (Object)(object)((Character)player).m_eye == (Object)null) { return false; } RaycastHit val = default(RaycastHit); if (!Physics.Raycast(((Component)GameCamera.instance).transform.position, ((Component)GameCamera.instance).transform.forward, ref val, 50f, player.m_removeRayMask)) { return false; } if (Vector3.Distance(((RaycastHit)(ref val)).point, ((Character)player).m_eye.position) >= player.m_maxPlaceDistance) { return false; } piece = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Piece>(); if (!Object.op_Implicit((Object)(object)piece) && Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponent<Heightmap>())) { piece = TerrainModifier.FindClosestModifierPieceInRange(((RaycastHit)(ref val)).point, 2.5f); } return (Object)(object)piece != (Object)null; } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "UpdatePlacement")] private static void Player_UpdatePlacement_Postfix(Player __instance, bool takeInput) { //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || !takeInput || !((Character)__instance).InPlaceMode() || ((Character)__instance).IsDead()) { return; } ItemData rightItem = ((Humanoid)__instance).GetRightItem(); if (!IsCultivator(rightItem) || !TryGetRemoveTarget(__instance, out var piece) || !IsTrackedPlantPiece(piece)) { return; } if (ZInput.GetButtonUp("Remove") || ZInput.GetButtonUp("JoyRemove")) { RemovePressedTimeRef.Invoke(__instance) = Time.time; } float num = RemovePressedTimeRef.Invoke(__instance); if (Time.time - num >= 0.2f || Time.time - LastToolUseTimeRef.Invoke(__instance) <= RemoveDelayRef.Invoke(__instance)) { return; } RemovePressedTimeRef.Invoke(__instance) = -9999f; if (!((Character)__instance).HaveStamina(rightItem.m_shared.m_attack.m_attackStamina)) { Hud.instance.StaminaBarEmptyFlash(); } else if (RemovePieceMethod(__instance)) { LastToolUseTimeRef.Invoke(__instance) = Time.time; ((Character)__instance).AddNoise(50f); ((Character)__instance).UseStamina(GetBuildStaminaMethod(__instance)); if ((int)__instance.m_buildPieces.m_skill != 0 && BuildRemoveDebtRef.Invoke(__instance) < 20) { BuildRemoveDebtRef.Invoke(__instance)++; } if (rightItem.m_shared.m_useDurability) { rightItem.m_durability -= GetPlaceDurabilityMethod(__instance, rightItem); } rightItem.m_shared.m_destroyEffect.Create(((Component)piece).transform.position, Quaternion.identity, (Transform)null, 1f, -1); } } [HarmonyPrefix] [HarmonyPatch(typeof(Player), "RemovePiece")] private static bool Player_RemovePiece_Prefix(Player __instance, ref bool __result) { if ((Object)(object)__instance == (Object)null) { return true; } if (!TryGetRemoveTarget(__instance, out var piece)) { return true; } if (!IsTrackedPlantPiece(piece)) { return true; } ItemData rightItem = ((Humanoid)__instance).GetRightItem(); if (IsCultivator(rightItem)) { return true; } __result = false; return false; } } [HarmonyPatch] internal static class Code_PlantationsPickableConfig { private sealed class PickableProfile { public string PiecePrefab; public string NormalDropPrefab; public string ExtraDropPrefab; public Func<int> GetDropAmount; public Func<int> GetExtraDropAmount; public Func<float> GetExtraDropChance; public Func<float> GetRespawnTimeMinutes; public Func<bool> GetVanillaSeedDropEnabled; } private const float RespawnUpdateInterval = 10f; private const float RespawnInvokeMinDelay = 1f; private const float RespawnInvokeMaxDelay = 2f; private static readonly Dictionary<string, PickableProfile> ModProfilesByPiece = new Dictionary<string, PickableProfile>(StringComparer.Ordinal) { ["RD_Dandelion"] = new PickableProfile { PiecePrefab = "RD_Dandelion", NormalDropPrefab = "Dandelion", ExtraDropPrefab = "RD_seed_dandelion", GetDropAmount = () => PlantationsPlugin.CE_RD_Dandelion_DropAmount.Value, GetExtraDropAmount = () => PlantationsPlugin.CE_RD_Dandelion_ExtraDropAmount.Value, GetExtraDropChance = () => PlantationsPlugin.CE_RD_Dandelion_ExtraDropChance.Value, GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_Dandelion_RespawnTimeMinutes.Value, GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_Dandelion_VanillaSeedDropEnabled.Value }, ["RD_Mushroom"] = new PickableProfile { PiecePrefab = "RD_Mushroom", NormalDropPrefab = "Mushroom", ExtraDropPrefab = "RD_red_spore", GetDropAmount = () => PlantationsPlugin.CE_RD_Mushroom_DropAmount.Value, GetExtraDropAmount = () => PlantationsPlugin.CE_RD_Mushroom_ExtraDropAmount.Value, GetExtraDropChance = () => PlantationsPlugin.CE_RD_Mushroom_ExtraDropChance.Value, GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_Mushroom_RespawnTimeMinutes.Value, GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_Mushroom_VanillaSeedDropEnabled.Value }, ["RD_Mushroom_yellow"] = new PickableProfile { PiecePrefab = "RD_Mushroom_yellow", NormalDropPrefab = "MushroomYellow", ExtraDropPrefab = "RD_yellow_spore", GetDropAmount = () => PlantationsPlugin.CE_RD_Mushroom_yellow_DropAmount.Value, GetExtraDropAmount = () => PlantationsPlugin.CE_RD_Mushroom_yellow_ExtraDropAmount.Value, GetExtraDropChance = () => PlantationsPlugin.CE_RD_Mushroom_yellow_ExtraDropChance.Value, GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_Mushroom_yellow_RespawnTimeMinutes.Value, GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_Mushroom_yellow_VanillaSeedDropEnabled.Value }, ["RD_RaspberryBush"] = new PickableProfile { PiecePrefab = "RD_RaspberryBush", NormalDropPrefab = "Raspberry", ExtraDropPrefab = "RD_seed_raspberry", GetDropAmount = () => PlantationsPlugin.CE_RD_RaspberryBush_DropAmount.Value, GetExtraDropAmount = () => PlantationsPlugin.CE_RD_RaspberryBush_ExtraDropAmount.Value, GetExtraDropChance = () => PlantationsPlugin.CE_RD_RaspberryBush_ExtraDropChance.Value, GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_RaspberryBush_RespawnTimeMinutes.Value, GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_RaspberryBush_VanillaSeedDropEnabled.Value }, ["RD_BlueberryBush"] = new PickableProfile { PiecePrefab = "RD_BlueberryBush", NormalDropPrefab = "Blueberries", ExtraDropPrefab = "RD_seed_blueberry", GetDropAmount = () => PlantationsPlugin.CE_RD_BlueberryBush_DropAmount.Value, GetExtraDropAmount = () => PlantationsPlugin.CE_RD_BlueberryBush_ExtraDropAmount.Value, GetExtraDropChance = () => PlantationsPlugin.CE_RD_BlueberryBush_ExtraDropChance.Value, GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_BlueberryBush_RespawnTimeMinutes.Value, GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_BlueberryBush_VanillaSeedDropEnabled.Value }, ["RD_thistle"] = new PickableProfile { PiecePrefab = "RD_thistle", NormalDropPrefab = "Thistle", ExtraDropPrefab = "RD_seed_thistle", GetDropAmount = () => PlantationsPlugin.CE_RD_thistle_DropAmount.Value, GetExtraDropAmount = () => PlantationsPlugin.CE_RD_thistle_ExtraDropAmount.Value, GetExtraDropChance = () => PlantationsPlugin.CE_RD_thistle_ExtraDropChance.Value, GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_thistle_RespawnTimeMinutes.Value, GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_thistle_VanillaSeedDropEnabled.Value }, ["RD_CloudberryBush"] = new PickableProfile { PiecePrefab = "RD_CloudberryBush", NormalDropPrefab = "Cloudberry", ExtraDropPrefab = "RD_seed_cloudberry", GetDropAmount = () => PlantationsPlugin.CE_RD_CloudberryBush_DropAmount.Value, GetExtraDropAmount = () => PlantationsPlugin.CE_RD_CloudberryBush_ExtraDropAmount.Value, GetExtraDropChance = () => PlantationsPlugin.CE_RD_CloudberryBush_ExtraDropChance.Value, GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_CloudberryBush_RespawnTimeMinutes.Value, GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_CloudberryBush_VanillaSeedDropEnabled.Value }, ["RD_MushroomSmokePuff"] = new PickableProfile { PiecePrefab = "RD_MushroomSmokePuff", NormalDropPrefab = "MushroomSmokePuff", ExtraDropPrefab = "RD_seed_smokepuff", GetDropAmount = () => PlantationsPlugin.CE_RD_MushroomSmokePuff_DropAmount.Value, GetExtraDropAmount = () => PlantationsPlugin.CE_RD_MushroomSmokePuff_ExtraDropAmount.Value, GetExtraDropChance = () => PlantationsPlugin.CE_RD_MushroomSmokePuff_ExtraDropChance.Value, GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_MushroomSmokePuff_RespawnTimeMinutes.Value, GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_MushroomSmokePuff_VanillaSeedDropEnabled.Value }, ["RD_Fiddlehead"] = new PickableProfile { PiecePrefab = "RD_Fiddlehead", NormalDropPrefab = "Fiddleheadfern", ExtraDropPrefab = "RD_seed_fiddlehead", GetDropAmount = () => PlantationsPlugin.CE_RD_Fiddlehead_DropAmount.Value, GetExtraDropAmount = () => PlantationsPlugin.CE_RD_Fiddlehead_ExtraDropAmount.Value, GetExtraDropChance = () => PlantationsPlugin.CE_RD_Fiddlehead_ExtraDropChance.Value, GetRespawnTimeMinutes = () => PlantationsPlugin.CE_RD_Fiddlehead_RespawnTimeMinutes.Value, GetVanillaSeedDropEnabled = () => PlantationsPlugin.CE_RD_Fiddlehead_VanillaSeedDropEnabled.Value } }; private static readonly Dictionary<string, PickableProfile> VanillaProfilesByPiece = new Dictionary<string, PickableProfile>(StringComparer.Ordinal) { ["Pickable_Dandelion"] = ModProfilesByPiece["RD_Dandelion"], ["Pickable_Mushroom"] = ModProfilesByPiece["RD_Mushroom"], ["Pickable_Mushroom_yellow"] = ModProfilesByPiece["RD_Mushroom_yellow"], ["RaspberryBush"] = ModProfilesByPiece["RD_RaspberryBush"], ["BlueberryBush"] = ModProfilesByPiece["RD_BlueberryBush"], ["Pickable_Thistle"] = ModProfilesByPiece["RD_thistle"], ["CloudberryBush"] = ModProfilesByPiece["RD_CloudberryBush"], ["Pickable_SmokePuff"] = ModProfilesByPiece["RD_MushroomSmokePuff"], ["Pickable_Fiddlehead"] = ModProfilesByPiece["RD_Fiddlehead"] }; private static string GetPieceName(GameObject obj) { if (!Object.op_Implicit((Object)(object)obj)) { return string.Empty; } string prefabName = Utils.GetPrefabName(obj); return string.IsNullOrEmpty(prefabName) ? ((Object)obj).name : prefabName; } private static bool TryGetModProfile(Pickable pickable, out PickableProfile profile) { profile = null; if ((Object)(object)pickable == (Object)null || !Object.op_Implicit((Object)(object)((Component)pickable).gameObject)) { return false; } return ModProfilesByPiece.TryGetValue(GetPieceName(((Component)pickable).gameObject), out profile); } private static bool TryGetVanillaProfile(Pickable pickable, out PickableProfile profile) { profile = null; if ((Object)(object)pickable == (Object)null || !Object.op_Implicit((Object)(object)((Component)pickable).gameObject)) { return false; } return VanillaProfilesByPiece.TryGetValue(GetPieceName(((Component)pickable).gameObject), out profile); } private static GameObject GetPrefab(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return null; } GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(prefabName) : null); if (Object.op_Implicit((Object)(object)val)) { return val; } return Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(prefabName) : null; } private static DropTable BuildExtraDropTable(PickableProfile profile) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown int num = profile.GetExtraDropAmount(); if (num <= 0) { return null; } float num2 = Mathf.Clamp01(profile.GetExtraDropChance()); if (num2 <= 0f) { return null; } GameObject prefab = GetPrefab(profile.ExtraDropPrefab); if (!Object.op_Implicit((Object)(object)prefab)) { return null; } return new DropTable { m_dropMin = 1, m_dropMax = 1, m_dropChance = num2, m_oneOfEach = false, m_drops = new List<DropData> { new DropData { m_item = prefab, m_stackMin = num, m_stackMax = num, m_weight = 1f, m_dontScale = false } } }; } private static void ApplyExtraDropsOnly(Pickable pickable, PickableProfile profile) { if (profile.GetVanillaSeedDropEnabled()) { pickable.m_extraDrops = BuildExtraDropTable(profile); } } private static void ApplyFullModConfig(Pickable pickable, PickableProfile profile) { GameObject prefab = GetPrefab(profile.NormalDropPrefab); if (Object.op_Implicit((Object)(object)prefab)) { pickable.m_itemPrefab = prefab; } int num = profile.GetDropAmount(); pickable.m_amount = ((num < 1) ? 1 : num); float num2 = profile.GetRespawnTimeMinutes(); pickable.m_respawnTimeMinutes = ((num2 < 0f) ? 0f : num2); pickable.m_extraDrops = BuildExtraDropTable(profile); } [HarmonyPrefix] [HarmonyPatch(typeof(Pickable), "Awake")] private static void Pickable_Awake_Prefix(Pickable __instance) { PickableProfile profile2; if (TryGetModProfile(__instance, out var profile)) { ApplyFullModConfig(__instance, profile); } else if (TryGetVanillaProfile(__instance, out profile2)) { ApplyExtraDropsOnly(__instance, profile2); } } [HarmonyPatch(typeof(Pickable), "Awake")] [HarmonyPostfix] private static void Pickable_Awake_Postfix(Pickable __instance) { if (TryGetModProfile(__instance, out var _) && !(__instance.m_respawnTimeMinutes <= 0f)) { ((MonoBehaviour)__instance).CancelInvoke("UpdateRespawn"); ((MonoBehaviour)__instance).InvokeRepeating("UpdateRespawn", Random.Range(1f, 2f), 10f); } } } public static class Registry_Effects { public static void RegistryEffects() { GameObject val = PrefabManager.RegisterPrefab("rd_plantations", "vfx_Place_smallitem_rd_plantations"); GameObject val2 = PrefabManager.RegisterPrefab("rd_plantations", "sfx_build_cultivator_rd_plantations"); GameObject val3 = PrefabManager.RegisterPrefab("rd_plantations", "vfx_bush_destroyed_rd_plantations"); GameObject val4 = PrefabManager.RegisterPrefab("rd_plantations", "vfx_bush_leaf_puff_rd_plantations"); GameObject val5 = PrefabManager.RegisterPrefab("rd_plantations", "sfx_bush_hit_rd_plantations"); GameObject val6 = PrefabManager.RegisterPrefab("rd_plantations", "sfx_pickable_pick_rd_plantations"); GameObject val7 = PrefabManager.RegisterPrefab("rd_plantations", "vfx_pickable_pick_rd_plantations"); } } [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)] [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] [BepInPlugin("radamanto.Plantations", "Plantations", "1.0.0")] public class PlantationsPlugin : BaseUnityPlugin { [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] private class ConfigurationManagerAttributes { public bool? Browsable = false; } [CompilerGenerated] private sealed class <ReloadConfigAfterQuietPeriod>d__65 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] private object <>2__current; public float quietSeconds; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] public PlantationsPlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] [return: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] [return: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] get { return <>2__current; } } [DebuggerHidden] public <ReloadConfigAfterQuietPeriod>d__65(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if ((DateTime.UtcNow - <>4__this._lastCfgWriteUtc).TotalSeconds < (double)quietSeconds) { <>2__current = null; <>1__state = 1; return true; } try { if (<>4__this._configWatcher == null || !<>4__this._watcherReady) { return false; } <>4__this._configWatcher.EnableRaisingEvents = false; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { ((BaseUnityPlugin)<>4__this).Config.Reload(); <>4__this._ignoreEventsUntilUtc = DateTime.UtcNow.AddSeconds(1.0); ((BaseUnityPlugin)<>4__this).Config.Save(); } } catch { } finally { if (<>4__this._configWatcher != null) { <>4__this._configWatcher.EnableRaisingEvents = true; } <>4__this._reloadScheduled = false; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } internal const string ModGUID = "radamanto.Plantations"; internal const string ModName = "Plantations"; internal const string ModVersion = "1.0.0"; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] internal static ManualLogSource Log; public static ConfigEntry<bool> CE_VanillaPlantTimerUI_Enabled; public static ConfigEntry<int> CE_RD_Dandelion_DropAmount; public static ConfigEntry<int> CE_RD_Dandelion_ExtraDropAmount; public static ConfigEntry<float> CE_RD_Dandelion_ExtraDropChance; public static ConfigEntry<bool> CE_RD_Dandelion_VanillaSeedDropEnabled; public static ConfigEntry<float> CE_RD_Dandelion_RespawnTimeMinutes; public static ConfigEntry<int> CE_RD_Mushroom_DropAmount; public static ConfigEntry<int> CE_RD_Mushroom_ExtraDropAmount; public static ConfigEntry<float> CE_RD_Mushroom_ExtraDropChance; public static ConfigEntry<bool> CE_RD_Mushroom_VanillaSeedDropEnabled; public static ConfigEntry<float> CE_RD_Mushroom_RespawnTimeMinutes; public static ConfigEntry<int> CE_RD_Mushroom_yellow_DropAmount; public static ConfigEntry<int> CE_RD_Mushroom_yellow_ExtraDropAmount; public static ConfigEntry<float> CE_RD_Mushroom_yellow_ExtraDropChance; public static ConfigEntry<bool> CE_RD_Mushroom_yellow_VanillaSeedDropEnabled; public static ConfigEntry<float> CE_RD_Mushroom_yellow_RespawnTimeMinutes; public static ConfigEntry<int> CE_RD_RaspberryBush_DropAmount; public static ConfigEntry<int> CE_RD_RaspberryBush_ExtraDropAmount; public static ConfigEntry<float> CE_RD_RaspberryBush_ExtraDropChance; public static ConfigEntry<bool> CE_RD_RaspberryBush_VanillaSeedDropEnabled; public static ConfigEntry<float> CE_RD_RaspberryBush_RespawnTimeMinutes; public static ConfigEntry<int> CE_RD_BlueberryBush_DropAmount; public static ConfigEntry<int> CE_RD_BlueberryBush_ExtraDropAmount; public static ConfigEntry<float> CE_RD_BlueberryBush_ExtraDropChance; public static ConfigEntry<bool> CE_RD_BlueberryBush_VanillaSeedDropEnabled; public static ConfigEntry<float> CE_RD_BlueberryBush_RespawnTimeMinutes; public static ConfigEntry<int> CE_RD_thistle_DropAmount; public static ConfigEntry<int> CE_RD_thistle_ExtraDropAmount; public static ConfigEntry<float> CE_RD_thistle_ExtraDropChance; public static ConfigEntry<bool> CE_RD_thistle_VanillaSeedDropEnabled; public static ConfigEntry<float> CE_RD_thistle_RespawnTimeMinutes; public static ConfigEntry<int> CE_RD_CloudberryBush_DropAmount; public static ConfigEntry<int> CE_RD_CloudberryBush_ExtraDropAmount; public static ConfigEntry<float> CE_RD_CloudberryBush_ExtraDropChance; public static ConfigEntry<bool> CE_RD_CloudberryBush_VanillaSeedDropEnabled; public static ConfigEntry<float> CE_RD_CloudberryBush_RespawnTimeMinutes; public static ConfigEntry<int> CE_RD_MushroomSmokePuff_DropAmount; public static ConfigEntry<int> CE_RD_MushroomSmokePuff_ExtraDropAmount; public static ConfigEntry<float> CE_RD_MushroomSmokePuff_ExtraDropChance; public static ConfigEntry<bool> CE_RD_MushroomSmokePuff_VanillaSeedDropEnabled; public static ConfigEntry<float> CE_RD_MushroomSmokePuff_RespawnTimeMinutes; public static ConfigEntry<int> CE_RD_Fiddlehead_DropAmount; public static ConfigEntry<int> CE_RD_Fiddlehead_ExtraDropAmount; public static ConfigEntry<float> CE_RD_Fiddlehead_ExtraDropChance; public static ConfigEntry<bool> CE_RD_Fiddlehead_VanillaSeedDropEnabled; public static ConfigEntry<float> CE_RD_Fiddlehead_RespawnTimeMinutes; private Harmony _harmony = null; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] internal static ConfigSync ConfigSync; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] private static ConfigEntry<bool> _serverConfigLocked; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] private FileSystemWatcher _configWatcher; private DateTime _lastCfgWriteUtc = DateTime.MinValue; private DateTime _ignoreEventsUntilUtc = DateTime.MinValue; private bool _reloadScheduled; private bool _watcherReady; private void Awake() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown Localizer.Load(); Log = ((BaseUnityPlugin)this).Logger; _harmony = new Harmony("radamanto.Plantations"); SetupServerSyncAndWatcher(); CE_VanillaPlantTimerUI_Enabled = Cfg("01 - General", "Vanilla Timer UI", defaultValue: true, "If true, all vanilla Plant-based crops also show the growth timer UI."); CE_RD_Dandelion_DropAmount = Cfg("02 - Dandelion", "02.01 - Dandelion Drop Amount", 3, "Dandelion drop amount."); CE_RD_Dandelion_ExtraDropAmount = Cfg("02 - Dandelion", "02.02 - Dandelion Seed Drop Amount", 1, "Dandelion seed drop amount."); CE_RD_Dandelion_ExtraDropChance = Cfg("02 - Dandelion", "02.03 - Dandelion Seed Drop Chance", 0.05f, "Chance for Dandelion seed to drop. 0 = never, 1 = always."); CE_RD_Dandelion_VanillaSeedDropEnabled = Cfg("02 - Dandelion", "02.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla Dandelion can also drop seed. If false, another external way to obtain seeds is required."); CE_RD_Dandelion_RespawnTimeMinutes = Cfg("02 - Dandelion", "02.05 - Dandelion Respawn Time Minutes", 60f, "Dandelion respawn time in minutes."); CE_RD_Mushroom_DropAmount = Cfg("03 - Mushroom", "03.01 - Mushroom Drop Amount", 3, "Mushroom drop amount."); CE_RD_Mushroom_ExtraDropAmount = Cfg("03 - Mushroom", "03.02 - Red Mushroom Spore Drop Amount", 1, "Red Mushroom spore drop amount."); CE_RD_Mushroom_ExtraDropChance = Cfg("03 - Mushroom", "03.03 - Red Mushroom Spore Drop Chance", 0.05f, "Chance for Red Mushroom spore to drop. 0 = never, 1 = always."); CE_RD_Mushroom_VanillaSeedDropEnabled = Cfg("03 - Mushroom", "03.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla Mushroom can also drop red spore. If false, another external way to obtain seeds is required."); CE_RD_Mushroom_RespawnTimeMinutes = Cfg("03 - Mushroom", "03.05 - Mushroom Respawn Time Minutes", 60f, "Mushroom respawn time in minutes."); CE_RD_Mushroom_yellow_DropAmount = Cfg("04 - Yellow Mushroom", "04.01 - Yellow Mushroom Drop Amount", 3, "Yellow Mushroom drop amount."); CE_RD_Mushroom_yellow_ExtraDropAmount = Cfg("04 - Yellow Mushroom", "04.02 - Yellow Mushroom Spore Drop Amount", 1, "Yellow Mushroom spore drop amount."); CE_RD_Mushroom_yellow_ExtraDropChance = Cfg("04 - Yellow Mushroom", "04.03 - Yellow Mushroom Spore Drop Chance", 0.05f, "Chance for Yellow Mushroom spore to drop. 0 = never, 1 = always."); CE_RD_Mushroom_yellow_VanillaSeedDropEnabled = Cfg("04 - Yellow Mushroom", "04.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla Yellow Mushroom can also drop spore. If false, another external way to obtain seeds is required."); CE_RD_Mushroom_yellow_RespawnTimeMinutes = Cfg("04 - Yellow Mushroom", "04.05 - Yellow Mushroom Respawn Time Minutes", 60f, "Yellow Mushroom respawn time in minutes."); CE_RD_RaspberryBush_DropAmount = Cfg("05 - Raspberry", "05.01 - Raspberry Drop Amount", 3, "Raspberry drop amount."); CE_RD_RaspberryBush_ExtraDropAmount = Cfg("05 - Raspberry", "05.02 - Raspberry Seed Drop Amount", 1, "Raspberry seed drop amount."); CE_RD_RaspberryBush_ExtraDropChance = Cfg("05 - Raspberry", "05.03 - Raspberry Seed Drop Chance", 0.05f, "Chance for Raspberry seed to drop. 0 = never, 1 = always."); CE_RD_RaspberryBush_VanillaSeedDropEnabled = Cfg("05 - Raspberry", "05.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla RaspberryBush can also drop seed. If false, another external way to obtain seeds is required."); CE_RD_RaspberryBush_RespawnTimeMinutes = Cfg("05 - Raspberry", "05.05 - Raspberry Respawn Time Minutes", 60f, "Raspberry respawn time in minutes."); CE_RD_BlueberryBush_DropAmount = Cfg("06 - Blueberry", "06.01 - Blueberry Drop Amount", 3, "Blueberry drop amount."); CE_RD_BlueberryBush_ExtraDropAmount = Cfg("06 - Blueberry", "06.02 - Blueberry Seed Drop Amount", 1, "Blueberry seed drop amount."); CE_RD_BlueberryBush_ExtraDropChance = Cfg("06 - Blueberry", "06.03 - Blueberry Seed Drop Chance", 0.05f, "Chance for Blueberry seed to drop. 0 = never, 1 = always."); CE_RD_BlueberryBush_VanillaSeedDropEnabled = Cfg("06 - Blueberry", "06.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla BlueberryBush can also drop seed. If false, another external way to obtain seeds is required."); CE_RD_BlueberryBush_RespawnTimeMinutes = Cfg("06 - Blueberry", "06.05 - Blueberry Respawn Time Minutes", 60f, "Blueberry respawn time in minutes."); CE_RD_thistle_DropAmount = Cfg("07 - Thistle", "07.01 - Thistle Drop Amount", 3, "Thistle drop amount."); CE_RD_thistle_ExtraDropAmount = Cfg("07 - Thistle", "07.02 - Thistle Seed Drop Amount", 1, "Thistle seed drop amount."); CE_RD_thistle_ExtraDropChance = Cfg("07 - Thistle", "07.03 - Thistle Seed Drop Chance", 0.05f, "Chance for Thistle seed to drop. 0 = never, 1 = always."); CE_RD_thistle_VanillaSeedDropEnabled = Cfg("07 - Thistle", "07.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla Thistle can also drop seed. If false, another external way to obtain seeds is required."); CE_RD_thistle_RespawnTimeMinutes = Cfg("07 - Thistle", "07.05 - Thistle Respawn Time Minutes", 60f, "Thistle respawn time in minutes."); CE_RD_CloudberryBush_DropAmount = Cfg("08 - Cloudberry", "08.01 - Cloudberry Drop Amount", 3, "Cloudberry drop amount."); CE_RD_CloudberryBush_ExtraDropAmount = Cfg("08 - Cloudberry", "08.02 - Cloudberry Seed Drop Amount", 1, "Cloudberry seed drop amount."); CE_RD_CloudberryBush_ExtraDropChance = Cfg("08 - Cloudberry", "08.03 - Cloudberry Seed Drop Chance", 0.05f, "Chance for Cloudberry seed to drop. 0 = never, 1 = always."); CE_RD_CloudberryBush_VanillaSeedDropEnabled = Cfg("08 - Cloudberry", "08.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla CloudberryBush can also drop seed. If false, another external way to obtain seeds is required."); CE_RD_CloudberryBush_RespawnTimeMinutes = Cfg("08 - Cloudberry", "08.05 - Cloudberry Respawn Time Minutes", 60f, "Cloudberry respawn time in minutes."); CE_RD_MushroomSmokePuff_DropAmount = Cfg("09 - Smoke Puff", "09.01 - Smoke Puff Drop Amount", 3, "Smoke Puff drop amount."); CE_RD_MushroomSmokePuff_ExtraDropAmount = Cfg("09 - Smoke Puff", "09.02 - Smoke Puff Seed Drop Amount", 1, "Smoke Puff seed drop amount."); CE_RD_MushroomSmokePuff_ExtraDropChance = Cfg("09 - Smoke Puff", "09.03 - Smoke Puff Seed Drop Chance", 0.05f, "Chance for Smoke Puff seed to drop. 0 = never, 1 = always."); CE_RD_MushroomSmokePuff_VanillaSeedDropEnabled = Cfg("09 - Smoke Puff", "09.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla Smoke Puff can also drop seed. If false, another external way to obtain seeds is required."); CE_RD_MushroomSmokePuff_RespawnTimeMinutes = Cfg("09 - Smoke Puff", "09.05 - Smoke Puff Respawn Time Minutes", 60f, "Smoke Puff respawn time in minutes."); CE_RD_Fiddlehead_DropAmount = Cfg("10 - Fiddlehead", "10.01 - Fiddlehead Drop Amount", 3, "Fiddlehead drop amount."); CE_RD_Fiddlehead_ExtraDropAmount = Cfg("10 - Fiddlehead", "10.02 - Fiddlehead Seed Drop Amount", 1, "Fiddlehead seed drop amount."); CE_RD_Fiddlehead_ExtraDropChance = Cfg("10 - Fiddlehead", "10.03 - Fiddlehead Seed Drop Chance", 0.05f, "Chance for Fiddlehead seed to drop. 0 = never, 1 = always."); CE_RD_Fiddlehead_VanillaSeedDropEnabled = Cfg("10 - Fiddlehead", "10.04 - Vanilla Seed Drop Enabled", defaultValue: true, "If true, vanilla Fiddlehead can also drop seed. If false, another external way to obtain seeds is required."); CE_RD_Fiddlehead_RespawnTimeMinutes = Cfg("10 - Fiddlehead", "10.05 - Fiddlehead Respawn Time Minutes", 60f, "Fiddlehead respawn time in minutes."); Registry_Seeds.RegistrySeeds(); Registry_Plantations.RegistryPlantations(); Registry_Effects.RegistryEffects(); _harmony.PatchAll(); } public static bool IsLocalPlayerAdmin() { return ConfigSync != null && ConfigSync.IsAdmin; } public void SetupServerSyncAndWatcher() { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown bool flag = false; try { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; ConfigSync = new ConfigSync(((BaseUnityPlugin)this).Info.Metadata.GUID) { DisplayName = ((BaseUnityPlugin)this).Info.Metadata.Name, CurrentVersion = ((BaseUnityPlugin)this).Info.Metadata.Version.ToString(), MinimumRequiredVersion = ((BaseUnityPlugin)this).Info.Metadata.Version.ToString() }; _serverConfigLocked = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - General", "LockConfiguration", true, new ConfigDescription("If true, the server locks synchronized configs.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Browsable = false } })); ConfigSync.AddLockingConfigEntry<bool>(_serverConfigLocked); SetupConfigWatcher(); flag = true; } catch { } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; if (flag) { ((BaseUnityPlugin)this).Config.Save(); } } } protected ConfigEntry<T> Cfg<[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] T>(string section, string key, T defaultValue, string description, bool synced = true) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return config(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synced); } private ConfigEntry<T> config<[<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags); ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val); try { SyncedConfigEntry<T> syncedConfigEntry = ((ConfigSync != null) ? ConfigSync.AddConfigEntry<T>(val2) : null); if (syncedConfigEntry != null) { syncedConfigEntry.SynchronizedConfig = synchronizedSetting; } } catch { } return val2; } private void SetupConfigWatcher() { try { if (_configWatcher != null) { _configWatcher.Dispose(); } string configPath = Paths.ConfigPath; string fileName = Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath); _configWatcher = new FileSystemWatcher(configPath, fileName) { IncludeSubdirectories = false, NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime) }; FileSystemEventHandler onConfigChanged = [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (object _, FileSystemEventArgs __) => { if (!(DateTime.UtcNow < _ignoreEventsUntilUtc)) { _lastCfgWriteUtc = DateTime.UtcNow; if (!_reloadScheduled) { _reloadScheduled = true; ((MonoBehaviour)this).StartCoroutine(ReloadConfigAfterQuietPeriod(0.75f)); } } }; _configWatcher.Changed += onConfigChanged; _configWatcher.Created += onConfigChanged; _configWatcher.Renamed += [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (object _, RenamedEventArgs __) => { onConfigChanged(_, __); }; _configWatcher.EnableRaisingEvents = true; _watcherReady = true; } catch { } } [IteratorStateMachine(typeof(<ReloadConfigAfterQuietPeriod>d__65))] private IEnumerator ReloadConfigAfterQuietPeriod(float quietSeconds) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ReloadConfigAfterQuietPeriod>d__65(0) { <>4__this = this, quietSeconds = quietSeconds }; } } internal static class Registry_Plantations { public static void RegistryPlantations() { BuildPiece buildPiece = new BuildPiece("rd_plantations", "RD_Dandelion"); buildPiece.Tool.Add("Cultivator"); buildPiece.Category.Set("Silvestres"); buildPiece.SpecialProperties.AdminOnly = false; buildPiece.SpecialProperties.NoConfig = true; buildPiece.RequiredItems.Add("RD_seed_dandelion", 1, recover: true); MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece.Prefab, MaterialReplacer.ShaderType.UseUnityShader); BuildPiece buildPiece2 = new BuildPiece("rd_plantations", "RD_Mushroom"); buildPiece2.Crafting.Set(PieceManager.CraftingTable.None); buildPiece2.Tool.Add("Cultivator"); buildPiece2.Category.Set("Silvestres"); buildPiece2.SpecialProperties.AdminOnly = false; buildPiece2.SpecialProperties.NoConfig = true; buildPiece2.RequiredItems.Add("RD_red_spore", 1, recover: true); MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece2.Prefab, MaterialReplacer.ShaderType.UseUnityShader); BuildPiece buildPiece3 = new BuildPiece("rd_plantations", "RD_Mushroom_yellow"); buildPiece3.Crafting.Set(PieceManager.CraftingTable.None); buildPiece3.Tool.Add("Cultivator"); buildPiece3.Category.Set("Silvestres"); buildPiece3.SpecialProperties.AdminOnly = false; buildPiece3.SpecialProperties.NoConfig = true; buildPiece3.RequiredItems.Add("RD_yellow_spore", 1, recover: true); MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece3.Prefab, MaterialReplacer.ShaderType.UseUnityShader); BuildPiece buildPiece4 = new BuildPiece("rd_plantations", "RD_RaspberryBush"); buildPiece4.Crafting.Set(PieceManager.CraftingTable.None); buildPiece4.Tool.Add("Cultivator"); buildPiece4.Category.Set("Silvestres"); buildPiece4.SpecialProperties.AdminOnly = false; buildPiece4.SpecialProperties.NoConfig = true; buildPiece4.RequiredItems.Add("RD_seed_raspberry", 1, recover: true); MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece4.Prefab, MaterialReplacer.ShaderType.UseUnityShader); BuildPiece buildPiece5 = new BuildPiece("rd_plantations", "RD_BlueberryBush"); buildPiece5.Crafting.Set(PieceManager.CraftingTable.None); buildPiece5.Tool.Add("Cultivator"); buildPiece5.Category.Set("Silvestres"); buildPiece5.SpecialProperties.AdminOnly = false; buildPiece5.SpecialProperties.NoConfig = true; buildPiece5.RequiredItems.Add("RD_seed_blueberry", 1, recover: true); MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece5.Prefab, MaterialReplacer.ShaderType.UseUnityShader); BuildPiece buildPiece6 = new BuildPiece("rd_plantations", "RD_thistle"); buildPiece6.Crafting.Set(PieceManager.CraftingTable.None); buildPiece6.Tool.Add("Cultivator"); buildPiece6.Category.Set("Silvestres"); buildPiece6.SpecialProperties.AdminOnly = false; buildPiece6.SpecialProperties.NoConfig = true; buildPiece6.RequiredItems.Add("RD_seed_thistle", 1, recover: true); MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece6.Prefab, MaterialReplacer.ShaderType.UseUnityShader); BuildPiece buildPiece7 = new BuildPiece("rd_plantations", "RD_CloudberryBush"); buildPiece7.Crafting.Set(PieceManager.CraftingTable.None); buildPiece7.Tool.Add("Cultivator"); buildPiece7.Category.Set("Silvestres"); buildPiece7.SpecialProperties.AdminOnly = false; buildPiece7.SpecialProperties.NoConfig = true; buildPiece7.RequiredItems.Add("RD_seed_cloudberry", 1, recover: true); MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece7.Prefab, MaterialReplacer.ShaderType.UseUnityShader); BuildPiece buildPiece8 = new BuildPiece("rd_plantations", "RD_MushroomSmokePuff"); buildPiece8.Crafting.Set(PieceManager.CraftingTable.None); buildPiece8.Tool.Add("Cultivator"); buildPiece8.Category.Set("Silvestres"); buildPiece8.SpecialProperties.AdminOnly = false; buildPiece8.SpecialProperties.NoConfig = true; buildPiece8.RequiredItems.Add("RD_seed_smokepuff", 1, recover: true); MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece8.Prefab, MaterialReplacer.ShaderType.UseUnityShader); BuildPiece buildPiece9 = new BuildPiece("rd_plantations", "RD_Fiddlehead"); buildPiece9.Crafting.Set(PieceManager.CraftingTable.None); buildPiece9.Tool.Add("Cultivator"); buildPiece9.Category.Set("Silvestres"); buildPiece9.SpecialProperties.AdminOnly = false; buildPiece9.SpecialProperties.NoConfig = true; buildPiece9.RequiredItems.Add("RD_seed_fiddlehead", 1, recover: true); MaterialReplacer.RegisterGameObjectForShaderSwap(buildPiece9.Prefab, MaterialReplacer.ShaderType.UseUnityShader); } } public static class Registry_Seeds { public static void RegistrySeeds() { Item item = new Item("rd_plantations", "RD_red_spore"); item.Configurable = Configurability.Disabled; Item item2 = new Item("rd_plantations", "RD_yellow_spore"); item2.Configurable = Configurability.Disabled; Item item3 = new Item("rd_plantations", "RD_seed_dandelion"); item3.Configurable = Configurability.Disabled; Item item4 = new Item("rd_plantations", "RD_seed_raspberry"); item4.Configurable = Configurability.Disabled; Item item5 = new Item("rd_plantations", "RD_seed_blueberry"); item5.Configurable = Configurability.Disabled; Item item6 = new Item("rd_plantations", "RD_seed_thistle"); item6.Configurable = Configurability.Disabled; Item item7 = new Item("rd_plantations", "RD_seed_cloudberry"); item7.Configurable = Configurability.Disabled; Item item8 = new Item("rd_plantations", "RD_seed_smokepuff"); item8.Configurable = Configurability.Disabled; Item item9 = new Item("rd_plantations", "RD_seed_fiddlehead"); item9.Configurable = Configurability.Disabled; } } [HarmonyPatch] internal static class Code_PlantationsStartEmpty { private const string CloneSuffix = "(Clone)"; private static readonly HashSet<int> AllowedPrefabHashes = new HashSet<int> { StringExtensionMethods.GetStableHashCode("RD_Dandelion"), StringExtensionMethods.GetStableHashCode("RD_Mushroom"), StringExtensionMethods.GetStableHashCode("RD_Mushroom_yellow"), StringExtensionMethods.GetStableHashCode("RD_RaspberryBush"), StringExtensionMethods.GetStableHashCode("RD_BlueberryBush"), StringExtensionMethods.GetStableHashCode("RD_thistle"), StringExtensionMethods.GetStableHashCode("RD_CloudberryBush"), StringExtensionMethods.GetStableHashCode("RD_MushroomSmokePuff"), StringExtensionMethods.GetStableHashCode("RD_Fiddlehead") }; private static readonly Dictionary<string, int> NameHashCache = new Dictionary<string, int>(32); private static readonly FieldRef<Pickable, ZNetView> PickableNViewRef = AccessTools.FieldRefAccess<Pickable, ZNetView>("m_nview"); private static int GetPrefabNameStableHash(string name) { if (string.IsNullOrEmpty(name)) { return 0; } if (NameHashCache.TryGetValue(name, out var value)) { return value; } string text = (name.EndsWith("(Clone)", StringComparison.Ordinal) ? name.Substring(0, name.Length - "(Clone)".Length) : name); value = StringExtensionMethods.GetStableHashCode(text); NameHashCache[name] = value; return value; } private static bool IsAllowed(GameObject obj) { if (!Object.op_Implicit((Object)(object)obj)) { return false; } return AllowedPrefabHashes.Contains(GetPrefabNameStableHash(((Object)obj).name)); } [HarmonyPostfix] [HarmonyPatch(typeof(Pickable), "Awake")] private static void Pickable_Awake_Postfix(Pickable __instance) { if ((Object)(object)__instance == (Object)null || !IsAllowed(((Component)__instance).gameObject) || __instance.m_respawnTimeMinutes <= 0f) { return; } ZNetView val = PickableNViewRef.Invoke(__instance); if (Object.op_Implicit((Object)(object)val) && val.IsValid() && val.IsOwner()) { ZDO zDO = val.GetZDO(); if (zDO != null && !zDO.GetBool(ZDOVars.s_picked, false) && zDO.GetLong(ZDOVars.s_pickedTime, 0L) == 0) { __instance.SetPicked(true); } } } } [HarmonyPatch] internal static class Code_PlantationsTimerUI { private const string TokenReady = "$ve_plantation_ready"; private const string TokenReadyIn = "$ve_plantation_ready_in"; private static readonly HashSet<string> AllowedPickables = new HashSet<string> { "RD_Dandelion", "RD_Mushroom", "RD_Mushroom_yellow", "RD_RaspberryBush", "RD_BlueberryBush", "RD_thistle", "RD_CloudberryBush", "RD_MushroomSmokePuff", "RD_Fiddlehead" }; private static readonly HashSet<string> AllowedPlants = new HashSet<string> { "RD_Dandelion", "RD_Mushroom", "RD_Mushroom_yellow", "RD_RaspberryBush", "RD_BlueberryBush", "RD_thistle", "RD_CloudberryBush", "RD_MushroomSmokePuff", "RD_Fiddlehead" }; private static readonly FieldRef<Plant, ZNetView> PlantNViewRef = AccessTools.FieldRefAccess<Plant, ZNetView>("m_nview"); private static readonly FieldRef<Pickable, ZNetView> PickableNViewRef = AccessTools.FieldRefAccess<Pickable, ZNetView>("m_nview"); private static readonly FieldRef<Pickable, bool> PickablePickedRef = AccessTools.FieldRefAccess<Pickable, bool>("m_picked"); private static readonly Func<Plant, float> PlantGetGrowTime = AccessTools.MethodDelegate<Func<Plant, float>>(AccessTools.DeclaredMethod(typeof(Plant), "GetGrowTime", (Type[])null, (Type[])null), (object)null, true); private static string GetPieceName(GameObject obj) { if (!Object.op_Implicit((Object)(object)obj)) { return string.Empty; } string prefabName = Utils.GetPrefabName(obj); return string.IsNullOrEmpty(prefabName) ? ((Object)obj).name : prefabName; } private static bool IsAllowedPickable(GameObject obj) { if (!Object.op_Implicit((Object)(object)obj)) { return false; } return AllowedPickables.Contains(GetPieceName(obj)); } private static bool IsAllowedPlant(GameObject obj) { if (!Object.op_Implicit((Object)(object)obj)) { return false; } string pieceName = GetPieceName(obj); if (AllowedPlants.Contains(pieceName)) { return true; } return PlantationsPlugin.CE_VanillaPlantTimerUI_Enabled.Value; } private static string FormatTime(double seconds) { if (seconds <= 0.0) { return string.Empty; } TimeSpan timeSpan = TimeSpan.FromSeconds(seconds); if (timeSpan.TotalHours >= 1.0) { return $"{timeSpan.Hours:D2}h {timeSpan.Minutes:D2}m {timeSpan.Seconds:D2}s"; } if (timeSpan.TotalMinutes >= 1.0) { return $"{timeSpan.Minutes:D2}m {timeSpan.Seconds:D2}s"; } return $"{timeSpan.Seconds:D2}s"; } private static string GetReadyLine() { return string.Format("<color=#00FF00>{0}</color>", Localization.instance.Localize("$ve_plantation_ready")); } private static string GetRemainingLine(double remainingSeconds) { return string.Format(Localization.instance.Localize("$ve_plantation_ready_in"), FormatTime(remainingSeconds)); } [HarmonyPatch(typeof(Pickable), "GetHoverText")] [HarmonyPostfix] private static void Pickable_GetHoverText_Postfix(Pickable __instance, ref string __result) { if ((Object)(object)__instance == (Object)null || !IsAllowedPickable(((Component)__instance).gameObject) || __instance.m_respawnTimeMinutes <= 0f || !PickablePickedRef.Invoke(__instance)) { return; } ZNetView val = PickableNViewRef.Invoke(__instance); ZDO val2 = (Object.op_Implicit((Object)(object)val) ? val.GetZDO() : null); if (val2 != null && !((Object)(object)ZNet.instance == (Object)null)) { long @long = val2.GetLong(ZDOVars.s_pickedTime, 0L); if (@long > 0) { DateTime dateTime = new DateTime(@long); TimeSpan timeSpan = ZNet.instance.GetTime() - dateTime; double num = (double)__instance.m_respawnTimeMinutes * 60.0; double num2 = num - timeSpan.TotalSeconds; string arg = Localization.instance.Localize(__instance.GetHoverName()); __result = ((num2 <= 0.0) ? $"{arg}\n{GetReadyLine()}" : $"{arg}\n{GetRemainingLine(num2)}"); } } } [HarmonyPatch(typeof(Plant), "GetHoverText")] [HarmonyPostfix] private static void Plant_GetHoverText_Postfix(Plant __instance, ref string __result) { if ((Object)(object)__instance == (Object)null || !IsAllowedPlant(((Component)__instance).gameObject)) { return; } ZNetView val = PlantNViewRef.Invoke(__instance); ZDO val2 = (Object.op_Implicit((Object)(object)val) ? val.GetZDO() : null); if (val2 != null && !((Object)(object)ZNet.instance == (Object)null)) { long @long = val2.GetLong(ZDOVars.s_plantTime, 0L); if (@long > 0) { DateTime dateTime = new DateTime(@long); double totalSeconds = (ZNet.instance.GetTime() - dateTime).TotalSeconds; float num = PlantGetGrowTime(__instance); double num2 = (double)num - totalSeconds; string text = ((num2 <= 0.0) ? GetReadyLine() : GetRemainingLine(num2)); __result = (string.IsNullOrEmpty(__result) ? text : $"{__result}\n{text}"); } } } } } namespace PieceManager { [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] [PublicAPI] [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)] public static class MaterialReplacer { [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] public enum ShaderType { PieceShader, VegetationShader, RockShader, RugShader, GrassShader, CustomCreature, UseUnityShader } private static readonly Dictionary<GameObject, bool> ObjectToSwap; private static readonly Dictionary<string, Material> OriginalMaterials; private static readonly Dictionary<GameObject, ShaderType> ObjectsForShaderReplace; private static readonly HashSet<Shader> CachedShaders; private static bool hasRun; static MaterialReplacer() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown CachedShaders = new HashSet<Shader>(); hasRun = false; OriginalMaterials = new Dictionary<string, Material>(); ObjectToSwap = new Dictionary<GameObject, bool>(); ObjectsForShaderReplace = new Dictionary<GameObject, ShaderType>(); Harmony val = new Harmony("org.bepinex.helpers.PieceManager"); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ZoneSystem), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(MaterialReplacer), "ReplaceAllMaterialsWithOriginal", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } public static void RegisterGameObjectForShaderSwap(GameObject go, ShaderType type) { if (!ObjectsForShaderReplace.ContainsKey(go)) { ObjectsForShaderReplace.Add(go, type); } } public static void RegisterGameObjectForMatSwap(GameObject go, bool isJotunnMock = false) { if (!((Object)(object)go == (Object)null) && !ObjectToSwap.ContainsKey(go)) { ObjectToSwap.Add(go, isJotunnMock); } } private static void GetAllMaterials() { Material[] array = Resources.FindObjectsOfTypeAll<Material>(); foreach (Material val in array) { OriginalMaterials[((Object)val).name] = val; } } [HarmonyPriority(700)] private static void ReplaceAllMaterialsWithOriginal() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)SystemInfo.graphicsDeviceType == 4 || hasRun) { return; } if (OriginalMaterials.Count == 0) { GetAllMaterials(); } foreach (KeyValuePair<GameObject, bool> item in ObjectToSwap) { GameObject key = item.Key; bool value = item.Value; ProcessGameObjectMaterials(key, value); } AssetBundle[] array = Resources.FindObjectsOfTypeAll<AssetBundle>(); AssetBundle[] array2 = array; foreach (AssetBundle val in array2) { IEnumerable<Shader> enumerable3; try { IEnumerable<Shader> enumerable2; if (!val.isStreamedSceneAssetBundle || !Object.op_Implicit((Object)(object)val)) { IEnumerable<Shader> enumerable = val.LoadAllAssets<Shader>(); enumerable2 = enumerable; } else { enumerable2 = from shader in ((IEnumerable<string>)val.GetAllAssetNames()).Select((Func<string, Shader>)val.LoadAsset<Shader>) where (Object)(object)shader != (Object)null select shader; } enumerable3 = enumerable2; } catch (Exception) { continue; } if (enumerable3 == null) { continue; } foreach (Shader item2 in enumerable3) { CachedShaders.Add(item2); } } foreach (KeyValuePair<GameObject, ShaderType> item3 in ObjectsForShaderReplace) { GameObject key2 = item3.Key; ShaderType value2 = item3.Value; ProcessGameObjectShaders(key2, value2); } hasRun = true; } private static void ProcessGameObjectMaterials(GameObject go, bool isJotunnMock) { Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true); Renderer[] array = componentsInChildren; foreach (Renderer val in array) { Material[] sharedMaterials = val.sharedMaterials.Select([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Material material) => ((Object)(object)material == (Object)null) ? null : ReplaceMaterial(material, isJotunnMock)).ToArray(); val.sharedMaterials = sharedMaterials; } } private static Material ReplaceMaterial(Material originalMaterial, bool isJotunnMock) { if ((Object)(object)originalMaterial == (Object)null) { return null; } string text = (isJotunnMock ? "JVLmock_" : "_REPLACE_"); if (!((Object)originalMaterial).name.StartsWith(text, StringComparison.Ordinal)) { return originalMaterial; } string text2 = ((Object)originalMaterial).name.Replace(" (Instance)", "").Replace(text, ""); if (OriginalMaterials.TryGetValue(text2, out var value)) { return value; } Debug.LogWarning((object)("No suitable material found to replace: " + text2)); return originalMaterial; } private static void ProcessGameObjectShaders(GameObject go, ShaderType shaderType) { Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true); Renderer[] array = componentsInChildren; foreach (Renderer val in array) { Material[] sharedMaterials = val.sharedMaterials; foreach (Material val2 in sharedMaterials) { if ((Object)(object)val2 != (Object)null) { val2.shader = GetShaderForType(val2.shader, shaderType, ((Object)val2.shader).name); } } } } private static Shader GetShaderForType(Shader orig, ShaderType shaderType, string originalShaderName) { return (Shader)(shaderType switch { ShaderType.PieceShader => FindShaderWithName(orig, "Custom/Piece"), ShaderType.VegetationShader => FindShaderWithName(orig, "Custom/Vegetation"), ShaderType.RockShader => FindShaderWithName(orig, "Custom/StaticRock"), ShaderType.RugShader => FindShaderWithName(orig, "Custom/Rug"), ShaderType.GrassShader => FindShaderWithName(orig, "Custom/Grass"), ShaderType.CustomCreature => FindShaderWithName(orig, "Custom/Creature"), ShaderType.UseUnityShader => FindShaderWithName(orig, ((Object)(object)FindShaderWithName(orig, originalShaderName) != (Object)null) ? originalShaderName : "ToonDeferredShading2017"), _ => FindShaderWithName(orig, "Standard"), }); } public static Shader FindShaderWithName(Shader origShader, string name) { foreach (Shader cachedShader in CachedShaders) { if (((Object)cachedShader).name == name) { return cachedShader; } } return origShader; } } [PublicAPI] public enum CraftingTable { None, [InternalName("piece_workbench")] Workbench, [InternalName("piece_cauldron")] Cauldron, [InternalName("forge")] Forge, [InternalName("piece_artisanstation")] ArtisanTable, [InternalName("piece_stonecutter")] StoneCutter, [InternalName("piece_magetable")] MageTable, [InternalName("blackforge")] BlackForge, [InternalName("piece_preptable")] FoodPreparationTable, [InternalName("piece_MeadCauldron")] MeadKetill, Custom } [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)] public class InternalName : Attribute { public readonly string internalName; public InternalName(string internalName) { this.internalName = internalName; } } [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)] [PublicAPI] public class ExtensionList { public readonly List<ExtensionConfig> ExtensionStations = new List<ExtensionConfig>(); public void Set(CraftingTable table, int maxStationDistance = 5) { ExtensionStations.Add(new ExtensionConfig { Table = table, maxStationDistance = maxStationDistance }); } public void Set(string customTable, int maxStationDistance = 5) { ExtensionStations.Add(new ExtensionConfig { Table = CraftingTable.Custom, custom = customTable, maxStationDistance = maxStationDistance }); } } public struct ExtensionConfig { public CraftingTable Table; public float maxStationDistance; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] public string custom; } [PublicAPI] [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)] [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] public class CraftingStationList { public readonly List<CraftingStationConfig> Stations = new List<CraftingStationConfig>(); public void Set(CraftingTable table) { Stations.Add(new CraftingStationConfig { Table = table }); } public void Set(string customTable) { Stations.Add(new CraftingStationConfig { Table = CraftingTable.Custom, custom = customTable }); } } public struct CraftingStationConfig { public CraftingTable Table; public int level; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] public string custom; } [PublicAPI] public enum BuildPieceCategory { Misc = 0, Crafting = 1, BuildingWorkbench = 2, BuildingStonecutter = 3, Furniture = 4, All = 100, Custom = 99 } [PublicAPI] [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)] [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] public class RequiredResourcesList { public readonly List<Requirement> Requirements = new List<Requirement>(); public void Add(string item, int amount, bool recover) { Requirements.Add(new Requirement { itemName = item, amount = amount, recover = recover }); } } public struct Requirement { [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(1)] public string itemName; public int amount; public bool recover; } public struct SpecialProperties { [Description("Admins should be the only ones that can build this piece.")] public bool AdminOnly; [Description("Turns off generating a config for this build piece.")] public bool NoConfig; } [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)] [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] [PublicAPI] public class BuildingPieceCategory { public BuildPieceCategory Category; public string custom = ""; public void Set(BuildPieceCategory category) { Category = category; } public void Set(string customCategory) { Category = BuildPieceCategory.Custom; custom = customCategory; } } [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)] [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] [PublicAPI] public class PieceTool { public readonly HashSet<string> Tools = new HashSet<string>(); public void Add(string tool) { Tools.Add(tool); } } [PublicAPI] [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(1)] public class BuildPiece { [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] internal class PieceConfig { public ConfigEntry<string> craft = null; public ConfigEntry<BuildPieceCategory> category = null; public ConfigEntry<string> customCategory = null; public ConfigEntry<string> tools = null; public ConfigEntry<CraftingTable> extensionTable = null; public ConfigEntry<string> customExtentionTable = null; public ConfigEntry<float> maxStationDistance = null; public ConfigEntry<CraftingTable> table = null; public ConfigEntry<string> customTable = null; } [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] private class ConfigurationManagerAttributes { [UsedImplicitly] public int? Order; [UsedImplicitly] public bool? Browsable; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] [UsedImplicitly] public string Category; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(new byte[] { 2, 1 })] [UsedImplicitly] public Action<ConfigEntryBase> CustomDrawer; } [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] private class SerializedRequirements { public readonly List<Requirement> Reqs; public SerializedRequirements(List<Requirement> reqs) { Reqs = reqs; } public SerializedRequirements(string reqs) { Reqs = reqs.Split(new char[1] { ',' }).Select([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (string r) => { string[] array = r.Split(new char[1] { ':' }); Requirement result = default(Requirement); result.itemName = array[0]; result.amount = ((array.Length <= 1 || !int.TryParse(array[1], out var result2)) ? 1 : result2); bool result3 = default(bool); result.recover = array.Length <= 2 || !bool.TryParse(array[2], out result3) || result3; return result; }).ToList(); } public override string ToString() { return string.Join(",", Reqs.Select([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Requirement r) => $"{r.itemName}:{r.amount}:{r.recover}")); } [return: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] public static ItemDrop fetchByName(ObjectDB objectDB, string name) { GameObject itemPrefab = objectDB.GetItemPrefab(name); ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)(((!string.IsNullOrWhiteSpace(((Object)plugin).name)) ? ("[" + ((Object)plugin).name + "]") : "") + " The required item '" + name + "' does not exist.")); } return val; } public static Requirement[] toPieceReqs(SerializedRequirements craft) { Dictionary<string, Requirement> dictionary = craft.Reqs.Where((Requirement r) => r.itemName != "").ToDictionary((Func<Requirement, string>)([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Requirement r) => r.itemName), (Func<Requirement, Requirement>)([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Requirement r) => { //IL_000d: 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_0025: Unknown result type (might be due to invalid IL or missing references) ItemDrop val = ResItem(r); return (val == null) ? ((Requirement)null) : new Requirement { m_amount = r.amount, m_resItem = val, m_recover = r.recover }; })); return dictionary.Values.Where([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Requirement v) => v != null).ToArray(); [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(2)] static ItemDrop ResItem(Requirement r) { return fetchByName(ObjectDB.instance, r.itemName); } } } [CompilerGenerated] private sealed class <RunQueuedSnapshots>d__33 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] private object <>2__current; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] private WaitForEndOfFrame <eof>5__1; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] private GameObject <prefab>5__2; private float <intensity>5__3; private Quaternion? <rot>5__4; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] private Exception <ex>5__5; object IEnumerator<object>.Current { [DebuggerHidden] [return: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] [return: <f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(0)] get { return <>2__current; } } [DebuggerHidden] public <RunQueuedSnapshots>d__33(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <eof>5__1 = null; <prefab>5__2 = null; <ex>5__5 = null; <>1__state = -2; } private bool MoveNext() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; <eof>5__1 = new WaitForEndOfFrame(); <>2__current = <eof>5__1; <>1__state = 2; return true; case 2: <>1__state = -1; break; case 3: <>1__state = -1; if (!Application.isBatchMode && Object.op_Implicit((Object)(object)<prefab>5__2)) { try { SnapshotPiece(<prefab>5__2, <intensity>5__3, <rot>5__4); } catch (Exception ex) { <ex>5__5 = ex; Debug.LogError((object)$"[PieceManager] Snapshot failed for '{((Object)<prefab>5__2).name}': {<ex>5__5}"); } } <prefab>5__2 = null; break; } if (_snapshotQueue.Count > 0) { (GameObject, float, Quaternion?) tuple = _snapshotQueue.Dequeue(); <prefab>5__2 = tuple.Item1; <intensity>5__3 = tuple.Item2; <rot>5__4 = tuple.Item3; <>2__current = <eof>5__1; <>1__state = 3; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } internal static readonly List<BuildPiece> registeredPieces = new List<BuildPiece>(); [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(new byte[] { 1, 0, 1 })] private static readonly Queue<(GameObject prefab, float lightIntensity, Quaternion? camRot)> _snapshotQueue = new Queue<(GameObject, float, Quaternion?)>(); private static readonly Dictionary<Piece, BuildPiece> pieceMap = new Dictionary<Piece, BuildPiece>(); internal static Dictionary<BuildPiece, PieceConfig> pieceConfigs = new Dictionary<BuildPiece, PieceConfig>(); internal List<Conversion> Conversions = new List<Conversion>(); internal List<ItemConversion> conversions = new List<ItemConversion>(); [Description("Disables generation of the configs for your pieces. This is global, this turns it off for all pieces in your mod.")] public static bool ConfigurationEnabled = true; public readonly GameObject Prefab; [Description("Specifies the resources needed to craft the piece.\nUse .Add to add resources with their internal ID and an amount.\nUse one .Add for each resource type the building piece should need.")] public readonly RequiredResourcesList RequiredItems = new RequiredResourcesList(); [Description("Sets the category for the building piece.")] public readonly BuildingPieceCategory Category = new BuildingPieceCategory(); [Description("Specifies the tool needed to build your piece.\nUse .Add to add a tool.")] public readonly PieceTool Tool = new PieceTool(); [Description("Specifies the crafting station needed to build your piece.\nUse .Add to add a crafting station, using the CraftingTable enum and a minimum level for the crafting station.")] public CraftingStationList Crafting = new CraftingStationList(); [Description("Makes this piece a station extension")] public ExtensionList Extension = new ExtensionList(); [Description("Change the extended/special properties of your build piece.")] public SpecialProperties SpecialProperties; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] [Description("Specifies a config entry which toggles whether a recipe is active.")] public ConfigEntryBase RecipeIsActive = null; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] private LocalizeKey _name; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] private LocalizeKey _description; internal string[] activeTools = null; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] private static object configManager; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] private static Localization _english; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] internal static BaseUnityPlugin _plugin = null; private static bool hasConfigSync = true; [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] private static object _configSync; public LocalizeKey Name { get { LocalizeKey name = _name; if (name != null) { return name; } Piece component = Prefab.GetComponent<Piece>(); if (component.m_name.StartsWith("$")) { _name = new LocalizeKey(component.m_name); } else { string text = "$piece_" + ((Object)Prefab).name.Replace(" ", "_"); _name = new LocalizeKey(text).English(component.m_name); component.m_name = text; } return _name; } } public LocalizeKey Description { get { LocalizeKey description = _description; if (description != null) { return description; } Piece component = Prefab.GetComponent<Piece>(); if (component.m_description.StartsWith("$")) { _description = new LocalizeKey(component.m_description); } else { string text = "$piece_" + ((Object)Prefab).name.Replace(" ", "_") + "_description"; _description = new LocalizeKey(text).English(component.m_description); component.m_description = text; } return _description; } } private static Localization english => _english ?? (_english = LocalizationCache.ForLanguage("English")); internal static BaseUnityPlugin plugin { get { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown if (_plugin != null) { return _plugin; } IEnumerable<TypeInfo> source; try { source = Assembly.GetExecutingAssembly().DefinedTypes.ToList(); } catch (ReflectionTypeLoadException ex) { source = from t in ex.Types where t != null select t.GetTypeInfo(); } _plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); return _plugin; } } [<f3227ed5-460d-44c0-9306-fa369a7eaa99>Nullable(2)] private static object configSync { [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(2)] get { if (_configSync != null || !hasConfigSync) { return _configSync; } Type type = Assembly.GetExecutingAssembly().GetType("ServerSync.ConfigSync"); if ((object)type != null) { _configSync = Activator.CreateInstance(type, plugin.Info.Metadata.GUID + " PieceManager"); type.GetField("CurrentVersion").SetValue(_configSync, plugin.Info.Metadata.Version.ToString()); type.GetProperty("IsLocked").SetValue(_configSync, true); } else { hasConfigSync = false; } return _configSync; } } public BuildPiece(string assetBundleFileName, string prefabName, string folderName = "assets") : this(PiecePrefabManager.RegisterAssetBundle(assetBundleFileName, folderName), prefabName) { } public BuildPiece(AssetBundle bundle, string prefabName) { Prefab = PiecePrefabManager.RegisterPrefab(bundle, prefabName); registeredPieces.Add(this); } internal static void Patch_FejdStartup(FejdStartup __instance) { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Expected O, but got Unknown //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Expected O, but got Unknown //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_040b: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Unknown result type (might be due to invalid IL or missing references) //IL_048c: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Expected O, but got Unknown //IL_0606: Unknown result type (might be due to invalid IL or missing references) //IL_0610: Expected O, but got Unknown //IL_08ea: Unknown result type (might be due to invalid IL or missing references) //IL_08f4: Expected O, but got Unknown //IL_067b: Unknown result type (might be due to invalid IL or missing references) //IL_0685: Expected O, but got Unknown //IL_0721: Unknown result type (might be due to invalid IL or missing references) //IL_072b: Expected O, but got Unknown //IL_095f: Unknown result type (might be due to invalid IL or missing references) //IL_0969: Expected O, but got Unknown //IL_0b7e: Unknown result type (might be due to invalid IL or missing references) //IL_0b88: Expected O, but got Unknown //IL_0c18: Unknown result type (might be due to invalid IL or missing references) //IL_0c22: Expected O, but got Unknown Type configManagerType = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Assembly a) => a.GetName().Name == "ConfigurationManager")?.GetType("ConfigurationManager.ConfigurationManager"); configManager = ((configManagerType == null) ? null : Chainloader.ManagerObject.GetComponent(configManagerType)); foreach (BuildPiece registeredPiece in registeredPieces) { registeredPiece.activeTools = registeredPiece.Tool.Tools.DefaultIfEmpty("Hammer").ToArray(); if (registeredPiece.Category.Category != BuildPieceCategory.Custom) { registeredPiece.Prefab.GetComponent<Piece>().m_category = (PieceCategory)registeredPiece.Category.Category; } else { registeredPiece.Prefab.GetComponent<Piece>().m_category = PiecePrefabManager.GetCategory(registeredPiece.Category.custom); } } if (!ConfigurationEnabled) { return; } bool saveOnConfigSet = plugin.Config.SaveOnConfigSet; plugin.Config.SaveOnConfigSet = false; foreach (BuildPiece registeredPiece2 in registeredPieces) { BuildPiece piece = registeredPiece2; if (piece.SpecialProperties.NoConfig) { continue; } PieceConfig pieceConfig2 = (pieceConfigs[piece] = new PieceConfig()); PieceConfig cfg = pieceConfig2; Piece piecePrefab2 = piece.Prefab.GetComponent<Piece>(); string pieceName = piecePrefab2.m_name; string englishName = new Regex("[=\\n\\t\\\\\"\\'\\[\\]]*").Replace(english.Localize(pieceName), "").Trim(); string localizedName = Localization.instance.Localize(pieceName).Trim(); int order = 0; cfg.category = config(englishName, "Build Table Category", piece.Category.Category, new ConfigDescription("Build Category where " + localizedName + " is available.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = (order -= 1), Category = localizedName } })); ConfigurationManagerAttributes customTableAttributes = new ConfigurationManagerAttributes { Order = (order -= 1), Browsable = (cfg.category.Value == BuildPieceCategory.Custom), Category = localizedName }; cfg.customCategory = config(englishName, "Custom Build Category", piece.Category.custom, new ConfigDescription("", (AcceptableValueBase)null, new object[1] { customTableAttributes })); cfg.category.SettingChanged += BuildTableConfigChanged; cfg.customCategory.SettingChanged += BuildTableConfigChanged; if (cfg.category.Value == BuildPieceCategory.Custom) { piecePrefab2.m_category = PiecePrefabManager.GetCategory(cfg.customCategory.Value); } else { piecePrefab2.m_category = (PieceCategory)cfg.category.Value; } cfg.tools = config(englishName, "Tools", string.Join(", ", piece.activeTools), new ConfigDescription("Comma separated list of tools where " + localizedName + " is available.", (AcceptableValueBase)null, new object[1] { customTableAttributes })); piece.activeTools = (from s in cfg.tools.Value.Split(new char[1] { ',' }) select s.Trim()).ToArray(); cfg.tools.SettingChanged += [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (object _, EventArgs _) => { Inventory[] source = (from c in Player.s_players.Select([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Player p) => ((Humanoid)p).GetInventory()).Concat(from c in Object.FindObjectsByType<Container>((FindObjectsSortMode)0) select c.GetInventory()) where c != null select c).ToArray(); Dictionary<string, List<PieceTable>> dictionary = (from kv in (from i in (from p in ObjectDB.instance.m_items select p.GetComponent<ItemDrop>() into c where Object.op_Implicit((Object)(object)c) && Object.op_Implicit((Object)(object)((Component)c).GetComponent<ZNetView>()) select c).Concat(ItemDrop.s_instances) select new KeyValuePair<string, ItemData>(Utils.GetPrefabName(((Component)i).gameObject), i.m_itemData)).Concat(from i in source.SelectMany([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (Inventory i) => i.GetAllItems()) select new KeyValuePair<string, ItemData>(((Object)i.m_dropPrefab).name, i)) where Object.op_Implicit((Object)(object)kv.Value.m_shared.m_buildPieces) group kv by kv.Key).ToDictionary([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (IGrouping<string, KeyValuePair<string, ItemData>> g) => g.Key, [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (IGrouping<string, KeyValuePair<string, ItemData>> g) => g.Select([<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (KeyValuePair<string, ItemData> kv) => kv.Value.m_shared.m_buildPieces).Distinct().ToList()); string[] array5 = piece.activeTools; foreach (string key in array5) { if (dictionary.TryGetValue(key, out var value3)) { foreach (PieceTable item3 in value3) { item3.m_pieces.Remove(piece.Prefab); } } } piece.activeTools = (from s in cfg.tools.Value.Split(new char[1] { ',' }) select s.Trim()).ToArray(); if (Object.op_Implicit((Object)(object)ObjectDB.instance)) { string[] array6 = piece.activeTools; foreach (string key2 in array6) { if (dictionary.TryGetValue(key2, out var value4)) { foreach (PieceTable item4 in value4) { if (!item4.m_pieces.Contains(piece.Prefab)) { item4.m_pieces.Add(piece.Prefab); } } } } if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)Player.m_localPlayer.m_buildPieces)) { PiecePrefabManager.CategoryRefreshNeeded = true; ((Humanoid)Player.m_localPlayer).SetPlaceMode(Player.m_localPlayer.m_buildPieces); } } }; StationExtension pieceExtensionComp; List<ConfigurationManagerAttributes> hideWhenNoneAttributes2; if (piece.Extension.ExtensionStations.Count > 0) { pieceExtensionComp = piece.Prefab.GetOrAddComponent<StationExtension>(); PieceConfig pieceConfig3 = cfg; string group = englishName; CraftingTable table = piece.Extension.ExtensionStations.First().Table; string text = "Crafting station that " + localizedName + " extends."; object[] array = new object[1]; ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes(); int num = order - 1; order = num; configurationManagerAttributes.Order = num; array[0] = configurationManagerAttributes; pieceConfig3.extensionTable = config(group, "Extends Station", table, new ConfigDescription(text, (AcceptableValueBase)null, array)); cfg.customExtentionTable = config(englishName, "Custom Extend Station", piece.Extension.ExtensionStations.First().custom ?? "", new ConfigDescription("", (AcceptableValueBase)null, new object[1] { customTableAttributes })); PieceConfig pieceConfig4 = cfg; string group2 = englishName; float maxStationDistance = piece.Extension.ExtensionStations.First().maxStationDistance; string text2 = "Distance from the station that " + localizedName + " can be placed."; object[] array2 = new object[1]; ConfigurationManagerAttributes configurationManagerAttributes2 = new ConfigurationManagerAttributes(); num = order - 1; order = num; configurationManagerAttributes2.Order = num; array2[0] = configurationManagerAttributes2; pieceConfig4.maxStationDistance = config(group2, "Max Station Distance", maxStationDistance, new ConfigDescription(text2, (AcceptableValueBase)null, array2)); hideWhenNoneAttributes2 = new List<ConfigurationManagerAttributes>(); cfg.extensionTable.SettingChanged += ExtensionTableConfigChanged; cfg.customExtentionTable.SettingChanged += ExtensionTableConfigChanged; cfg.maxStationDistance.SettingChanged += ExtensionTableConfigChanged; ConfigurationManagerAttributes configurationManagerAttributes3 = new ConfigurationManagerAttributes(); num = order - 1; order = num; configurationManagerAttributes3.Order = num; configurationManagerAttributes3.Browsable = cfg.extensionTable.Value != CraftingTable.None; ConfigurationManagerAttributes item = configurationManagerAttributes3; hideWhenNoneAttributes2.Add(item); } List<ConfigurationManagerAttributes> hideWhenNoneAttributes; if (piece.Crafting.Stations.Count > 0) { hideWhenNoneAttributes = new List<ConfigurationManagerAttributes>(); PieceConfig pieceConfig5 = cfg; string group3 = englishName; CraftingTable table2 = piece.Crafting.Stations.First().Table; string text3 = "Crafting station where " + localizedName + " is available."; object[] array3 = new object[1]; ConfigurationManagerAttributes configurationManagerAttributes4 = new ConfigurationManagerAttributes(); int num = order - 1; order = num; configurationManagerAttributes4.Order = num; array3[0] = configurationManagerAttributes4; pieceConfig5.table = config(group3, "Crafting Station", table2, new ConfigDescription(text3, (AcceptableValueBase)null, array3)); cfg.customTable = config(englishName, "Custom Crafting Station", piece.Crafting.Stations.First().custom ?? "", new ConfigDescription("", (AcceptableValueBase)null, new object[1] { customTableAttributes })); cfg.table.SettingChanged += TableConfigChanged; cfg.customTable.SettingChanged += TableConfigChanged; ConfigurationManagerAttributes configurationManagerAttributes5 = new ConfigurationManagerAttributes(); num = order - 1; order = num; configurationManagerAttributes5.Order = num; configurationManagerAttributes5.Browsable = cfg.table.Value != CraftingTable.None; ConfigurationManagerAttributes item2 = configurationManagerAttributes5; hideWhenNoneAttributes.Add(item2); } cfg.craft = itemConfig("Crafting Costs", new SerializedRequirements(piece.RequiredItems.Requirements).ToString(), "Item costs to craft " + localizedName); cfg.craft.SettingChanged += [<c2cbe57f-1fbc-4ac4-887f-f2eac4cc03cc>NullableContext(0)] (object _, EventArgs _) => { if (Object.op_Imp