Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Plantations v1.0.4
plugins/Plantations.dll
Decompiled a month 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 Splatform; using TMPro; using UnityEngine; using UnityEngine.Audio; 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.4")] [assembly: AssemblyCompany("Radamanto")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.4.0")] [module: <1af70648-03dc-4cf0-aa1a-92525b356746>RefSafetyRules(11)] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [<ac36e783-d8a0-4059-8544-836f43818104>Embedded] internal sealed class <ac36e783-d8a0-4059-8544-836f43818104>EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [<ac36e783-d8a0-4059-8544-836f43818104>Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class <ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>NullableAttribute : Attribute { public readonly byte[] NullableFlags; public <ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public <ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [<ac36e783-d8a0-4059-8544-836f43818104>Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class <751c224d-bfbf-4350-9e31-32d445024a3b>NullableContextAttribute : Attribute { public readonly byte Flag; public <751c224d-bfbf-4350-9e31-32d445024a3b>NullableContextAttribute(byte P_0) { Flag = P_0; } } [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] [CompilerGenerated] [<ac36e783-d8a0-4059-8544-836f43818104>Embedded] internal sealed class <1af70648-03dc-4cf0-aa1a-92525b356746>RefSafetyRulesAttribute : Attribute { public readonly int Version; public <1af70648-03dc-4cf0-aa1a-92525b356746>RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LocalizationManager { [<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>Nullable(0)] [<751c224d-bfbf-4350-9e31-32d445024a3b>NullableContext(1)] [PublicAPI] 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; [<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>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([<751c224d-bfbf-4350-9e31-32d445024a3b>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); } return _plugin; } } [<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>Nullable(2)] [method: <751c224d-bfbf-4350-9e31-32d445024a3b>NullableContext(2)] [field: <ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>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, [<751c224d-bfbf-4350-9e31-32d445024a3b>NullableContext(0)] (string current, KeyValuePair<string, Func<string>> kv) => current.Replace("{" + kv.Key + "}", kv.Value())); } if (key == "ve_plantation_ready_in") { text = text.Replace("{0}", "<color=yellow>{0}</color>"); } localization.AddWord(key, text); } public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, [<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>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 += [<751c224d-bfbf-4350-9e31-32d445024a3b>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() { LoadLocalization(Localization.instance, Localization.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: <ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>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; } [<751c224d-bfbf-4350-9e31-32d445024a3b>NullableContext(2)] public static byte[] ReadEmbeddedFileBytes([<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>Nullable(1)] string resourceFileName, Assembly containingAssembly = null) { using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([<751c224d-bfbf-4350-9e31-32d445024a3b>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 { [<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>Nullable(1)] public const string Version = "1.4.1"; } } namespace Plantations { [HarmonyPatch] internal static class Code_PlantationsRemoval { private sealed class TableCache { public int PieceCount = -1; public readonly HashSet<int> TrackedHashes = new HashSet<int>(); } private const string Feature = "Code_PlantationsRemoval"; private const float RemoveRayDistance = 50f; private const float TerrainModifierSearchRange = 2.5f; private static readonly Dictionary<PieceTable, TableCache> TableCaches = new Dictionary<PieceTable, TableCache>(); private static PieceTable _forcedTable; private static Player _rayPlayer; private static Piece _rayPiece; private static bool Prepare() { return PatchSafety.IsEnabled("Code_PlantationsRemoval"); } private static bool IsTrackedPlantPiece(Piece piece) { return Object.op_Implicit((Object)(object)piece) && PlantDefinitions.IsPieceHash(PlantDefinitions.GetPrefabHash(((Component)piece).gameObject)); } private static PieceTable GetToolTable(Player player) { return (Object.op_Implicit((Object)(object)player) ? ((Humanoid)player).GetRightItem() : null)?.m_shared?.m_buildPieces; } private static bool TableContainsPiece(PieceTable table, Piece piece) { if (!Object.op_Implicit((Object)(object)table) || !Object.op_Implicit((Object)(object)piece) || table.m_pieces == null) { return false; } if (!TableCaches.TryGetValue(table, out var value)) { value = new TableCache(); TableCaches[table] = value; } if (value.PieceCount != table.m_pieces.Count) { value.TrackedHashes.Clear(); foreach (GameObject piece2 in table.m_pieces) { if (Object.op_Implicit((Object)(object)piece2)) { int nameHash = PlantDefinitions.GetNameHash(((Object)piece2).name); if (PlantDefinitions.TryGetByPieceHash(nameHash, out var def)) { value.TrackedHashes.Add(nameHash); value.TrackedHashes.Add(def.PieceHash); } } } value.PieceCount = table.m_pieces.Count; } return value.TrackedHashes.Contains(PlantDefinitions.GetPrefabHash(((Component)piece).gameObject)); } private static bool TryGetRemoveTarget(Player player, out Piece piece) { if ((Object)(object)_forcedTable != (Object)null && _rayPlayer == player) { piece = _rayPiece; return (Object)(object)piece != (Object)null; } piece = RaycastRemoveTarget(player); _rayPlayer = player; _rayPiece = piece; return (Object)(object)piece != (Object)null; } private static Piece RaycastRemoveTarget(Player player) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_00c7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)GameCamera.instance == (Object)null || (Object)(object)((Character)player).m_eye == (Object)null) { return null; } Transform transform = ((Component)GameCamera.instance).transform; RaycastHit val = default(RaycastHit); if (!Physics.Raycast(transform.position, transform.forward, ref val, 50f, player.m_removeRayMask)) { return null; } if (Vector3.Distance(((RaycastHit)(ref val)).point, ((Character)player).m_eye.position) >= player.m_maxPlaceDistance) { return null; } Piece val2 = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Piece>(); if (!Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponent<Heightmap>())) { val2 = TerrainModifier.FindClosestModifierPieceInRange(((RaycastHit)(ref val)).point, 2.5f); } return Object.op_Implicit((Object)(object)val2) ? val2 : null; } [HarmonyPatch(typeof(Player), "UpdatePlacement")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Player_UpdatePlacement_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); FieldInfo objB = AccessTools.DeclaredField(typeof(Player), "m_removePressedTime"); MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(Time), "time"); MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(Code_PlantationsRemoval), "OnRemovePressed", (Type[])null, (Type[])null); int num = 0; for (int i = 1; i < list.Count; i++) { if (!(list[i].opcode != OpCodes.Stfld) && object.Equals(list[i].operand, objB) && CodeInstructionExtensions.Calls(list[i - 1], methodInfo)) { list.InsertRange(i + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)methodInfo2) }); num++; i += 2; } } if (num != 1) { throw new InvalidOperationException("Native remove input sequence not found."); } return list; } private static void OnRemovePressed(Player player) { if (!PatchSafety.IsEnabled("Code_PlantationsRemoval")) { return; } try { TryForceRemoveFlag(player, takeInput: true); } catch (Exception error) { PatchSafety.Fail("Code_PlantationsRemoval", error); } } [MethodImpl(MethodImplOptions.NoInlining)] private static PieceTable TryForceRemoveFlag(Player player, bool takeInput) { if (!takeInput || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return null; } if (!((Character)player).InPlaceMode() || ((Character)player).IsDead()) { return null; } if (Hud.IsPieceSelectionVisible()) { return null; } PieceTable toolTable = GetToolTable(player); if (!Object.op_Implicit((Object)(object)toolTable) || toolTable.m_canRemovePieces) { return null; } if (!TryGetRemoveTarget(player, out var piece)) { return null; } if (!IsTrackedPlantPiece(piece) || !TableContainsPiece(toolTable, piece)) { return null; } toolTable.m_canRemovePieces = true; _forcedTable = toolTable; return toolTable; } [HarmonyFinalizer] [HarmonyPatch(typeof(Player), "UpdatePlacement")] private static Exception Player_UpdatePlacement_Finalizer(Exception __exception) { if ((Object)(object)_forcedTable != (Object)null) { _forcedTable.m_canRemovePieces = false; } _forcedTable = null; _rayPlayer = null; _rayPiece = null; return __exception; } [HarmonyPatch(typeof(Player), "RemovePiece")] [HarmonyPrefix] private static bool Player_RemovePiece_Prefix(Player __instance, ref bool __result) { if (!PatchSafety.IsEnabled("Code_PlantationsRemoval")) { return true; } try { if (AllowRemove(__instance)) { return true; } __result = false; return false; } catch (Exception error) { PatchSafety.Fail("Code_PlantationsRemoval", error); return true; } } [MethodImpl(MethodImplOptions.NoInlining)] private static bool AllowRemove(Player player) { if ((Object)(object)player == (Object)null) { return true; } if (!TryGetRemoveTarget(player, out var piece)) { return true; } if (IsTrackedPlantPiece(piece)) { return TableContainsPiece(GetToolTable(player), piece); } return (Object)(object)_forcedTable == (Object)null; } } [HarmonyPatch] internal static class Code_PlantationsHarvest { private static readonly HashSet<Pickable> LoadedPlants = new HashSet<Pickable>(); private const string Feature = "Code_PlantationsHarvest"; private const float RespawnUpdateInterval = 10f; private const float RespawnInvokeMinDelay = 1f; private const float RespawnInvokeMaxDelay = 2f; private const string UpdateRespawnMethod = "UpdateRespawn"; private static bool Prepare() { return PatchSafety.IsEnabled("Code_PlantationsHarvest"); } internal static void ClearLoadedPlants() { LoadedPlants.Clear(); } internal static void RefreshLoadedPlants() { if (!PatchSafety.IsEnabled("Code_PlantationsHarvest")) { return; } try { LoadedPlants.RemoveWhere((Pickable pickable) => !Object.op_Implicit((Object)(object)pickable)); foreach (Pickable loadedPlant in LoadedPlants) { if (PlantDefinitions.TryGetPiece(((Component)loadedPlant).gameObject, out var def)) { ApplyFullModConfig(loadedPlant, def); } } } catch (Exception error) { PatchSafety.Fail("Code_PlantationsHarvest", error); } } [HarmonyPatch(typeof(ZNetView), "OnDestroy")] [HarmonyPostfix] private static void ZNetView_OnDestroy_Postfix(ZNetView __instance) { Pickable component = ((Component)__instance).GetComponent<Pickable>(); if (Object.op_Implicit((Object)(object)component)) { LoadedPlants.Remove(component); } } internal static float SanitizeRespawnMinutes(float minutes) { if (float.IsNaN(minutes) || float.IsInfinity(minutes)) { return 60f; } return Mathf.Clamp(minutes, 1f, 100000f); } private static void ApplyFullModConfig(Pickable pickable, PlantDefinition def) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = PlantDefinitions.GetPrefab(def.NormalDropPrefab); if (Object.op_Implicit((Object)(object)prefab)) { pickable.m_itemPrefab = prefab; } pickable.m_amount = Mathf.Max(1, def.DropAmount()); pickable.m_respawnTimeMinutes = SanitizeRespawnMinutes(def.RespawnMinutes()); pickable.m_extraDrops = (DropTable)(((object)PlantDefinitions.GetSeedTable(def)) ?? ((object)new DropTable())); } [HarmonyPrefix] [HarmonyPatch(typeof(Pickable), "Awake")] private static void Pickable_Awake_Prefix(Pickable __instance) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown if (!PatchSafety.IsEnabled("Code_PlantationsHarvest")) { return; } try { AwakePrefix(__instance); } catch (Exception error) { PatchSafety.Fail("Code_PlantationsHarvest", error); } finally { if (Object.op_Implicit((Object)(object)__instance) && __instance.m_extraDrops == null) { __instance.m_extraDrops = new DropTable(); } } } [MethodImpl(MethodImplOptions.NoInlining)] private static void AwakePrefix(Pickable pickable) { if (Object.op_Implicit((Object)(object)pickable) && PlantDefinitions.TryGetPiece(((Component)pickable).gameObject, out var def)) { ApplyFullModConfig(pickable, def); } } [HarmonyPatch(typeof(Pickable), "Awake")] [HarmonyPostfix] private static void Pickable_Awake_Postfix(Pickable __instance) { if (!PatchSafety.IsEnabled("Code_PlantationsHarvest")) { return; } try { AwakePostfix(__instance); } catch (Exception error) { PatchSafety.Fail("Code_PlantationsHarvest", error); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void AwakePostfix(Pickable pickable) { if (Object.op_Implicit((Object)(object)pickable)) { ZNetView nview = pickable.m_nview; if (Object.op_Implicit((Object)(object)nview) && nview.IsValid() && !(pickable.m_respawnTimeMinutes <= 0f) && PlantDefinitions.TryGetPiece(((Component)pickable).gameObject, out var _)) { LoadedPlants.Add(pickable); ((MonoBehaviour)pickable).CancelInvoke("UpdateRespawn"); ((MonoBehaviour)pickable).InvokeRepeating("UpdateRespawn", Random.Range(1f, 2f), 10f); } } } [HarmonyPatch(typeof(Pickable), "RPC_Pick")] [HarmonyPrefix] private static void Pickable_RPC_Pick_Prefix(Pickable __instance, out bool __state) { __state = false; if (!PatchSafety.IsEnabled("Code_PlantationsHarvest")) { return; } try { __state = WillVanillaPick(__instance); } catch (Exception error) { PatchSafety.Fail("Code_PlantationsHarvest", error); } } [MethodImpl(MethodImplOptions.NoInlining)] private static bool WillVanillaPick(Pickable pickable) { if (!Object.op_Implicit((Object)(object)pickable)) { return false; } ZNetView nview = pickable.m_nview; return Object.op_Implicit((Object)(object)nview) && nview.IsValid() && nview.IsOwner() && !pickable.m_picked; } [HarmonyPostfix] [HarmonyPatch(typeof(Pickable), "RPC_Pick")] private static void Pickable_RPC_Pick_Postfix(Pickable __instance, bool __state) { if (!__state || !PatchSafety.IsEnabled("Code_PlantationsHarvest")) { return; } try { DropVanillaSeed(__instance); } catch (Exception error) { PatchSafety.Fail("Code_PlantationsHarvest", error); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void DropVanillaSeed(Pickable pickable) { if (!PlantDefinitions.TryGetVanilla(((Component)pickable).gameObject, out var def) || !def.VanillaSeedDropEnabled()) { return; } int num = def.SeedAmount(); float num2 = Mathf.Clamp01(def.SeedChance()); if (num > 0 && !(num2 <= 0f) && !(Random.value > num2)) { GameObject prefab = PlantDefinitions.GetPrefab(def.SeedPrefab); if (Object.op_Implicit((Object)(object)prefab)) { pickable.Drop(prefab, pickable.m_amount + 1, num); } } } } [HarmonyPatch(typeof(Player), "Interact")] internal static class Code_PlantationsAreaHarvest { private static ConfigEntry<bool> Enabled; private static ConfigEntry<float> Radius; internal static void Initialize(ConfigFile config) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown Enabled = config.Bind<bool>("18 - Area Harvest", "18.01 - Enabled", true, "Hold Left Shift or Right Shift and use the game's interact key (default E) on a plant to harvest nearby pickables. Uses native harvesting without replanting."); Radius = config.Bind<float>("18 - Area Harvest", "18.02 - Radius", 6f, new ConfigDescription("Harvest radius in metres around the selected plant. Only loaded pickables are harvested.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>())); } [HarmonyPrefix] private static void Prefix(Player __instance, GameObject go, bool hold, out Pickable __state) { __state = null; if (Enabled == null || !Enabled.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)go) || ((Character)__instance).InAttack() || ((Character)__instance).InDodge() || (hold && Time.time - __instance.m_lastHoverInteractTime < 0.2f) || (!ZInput.GetKey((KeyCode)304, false) && !ZInput.GetKey((KeyCode)303, false))) { return; } Pickable componentInParent = go.GetComponentInParent<Pickable>(); if (!Object.op_Implicit((Object)(object)componentInParent) || !Object.op_Implicit((Object)(object)componentInParent.m_nview) || !componentInParent.m_nview.IsValid() || componentInParent.m_picked || componentInParent.m_pickedLocal || componentInParent.m_enabled == 0) { return; } if (componentInParent.m_tarPreventsPicking) { Floating component = ((Component)componentInParent).GetComponent<Floating>(); if (component != null && component.IsInTar()) { return; } } __state = componentInParent; } [HarmonyPostfix] private static void Postfix(Player __instance, Pickable __state, bool alt) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)__state) || !__state.m_pickedLocal) { return; } HashSet<Pickable> hashSet = new HashSet<Pickable> { __state }; Collider[] array = Physics.OverlapSphere(((Component)__state).transform.position, Radius.Value, PlantationsGridCollisions.CollisionMask); foreach (Collider val in array) { Pickable componentInParent = ((Component)val).GetComponentInParent<Pickable>(); if (Object.op_Implicit((Object)(object)componentInParent) && hashSet.Add(componentInParent) && Object.op_Implicit((Object)(object)componentInParent.m_nview) && componentInParent.m_nview.IsValid() && !componentInParent.m_picked && !componentInParent.m_pickedLocal && componentInParent.m_enabled != 0) { componentInParent.Interact((Humanoid)(object)__instance, false, alt); } } } } [HarmonyPatch(typeof(AudioMan), "Awake")] internal static class Code_PlantationsAudioMixer { private static AssetBundle Bundle; internal static void Initialize() { //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) { Bundle = PrefabManager.RegisterAssetBundle("rd_plantations"); Route(AudioMan.instance); } } [HarmonyPostfix] private static void Postfix(AudioMan __instance) { if ((Object)(object)__instance == (Object)(object)AudioMan.instance) { Route(__instance); } } private static void Route(AudioMan audioMan) { if (!Object.op_Implicit((Object)(object)Bundle) || !Object.op_Implicit((Object)(object)audioMan) || !Object.op_Implicit((Object)(object)audioMan.m_masterMixer)) { return; } AudioMixerGroup val = null; AudioMixerGroup[] array = audioMan.m_masterMixer.FindMatchingGroups(string.Empty); foreach (AudioMixerGroup val2 in array) { if (Object.op_Implicit((Object)(object)val2) && string.Equals(((Object)val2).name, "SFX", StringComparison.OrdinalIgnoreCase)) { val = val2; break; } } if (!Object.op_Implicit((Object)(object)val)) { return; } HashSet<AudioSource> hashSet = new HashSet<AudioSource>(); HashSet<AudioMixer> hashSet2 = new HashSet<AudioMixer>(); GameObject[] array2 = Bundle.LoadAllAssets<GameObject>(); foreach (GameObject val3 in array2) { if (!Object.op_Implicit((Object)(object)val3)) { continue; } AudioSource[] componentsInChildren = val3.GetComponentsInChildren<AudioSource>(true); foreach (AudioSource val4 in componentsInChildren) { hashSet.Add(val4); if (Object.op_Implicit((Object)(object)val4.outputAudioMixerGroup) && Object.op_Implicit((Object)(object)val4.outputAudioMixerGroup.audioMixer)) { hashSet2.Add(val4.outputAudioMixerGroup.audioMixer); } } } AudioSource[] array3 = Resources.FindObjectsOfTypeAll<AudioSource>(); foreach (AudioSource val5 in array3) { if (Object.op_Implicit((Object)(object)val5) && Object.op_Implicit((Object)(object)val5.outputAudioMixerGroup) && hashSet2.Contains(val5.outputAudioMixerGroup.audioMixer)) { hashSet.Add(val5); } } foreach (AudioSource item in hashSet) { if (Object.op_Implicit((Object)(object)item)) { item.outputAudioMixerGroup = val; } } } } internal static class PatchSafety { private static readonly HashSet<string> DisabledFeatures = new HashSet<string>(StringComparer.Ordinal); internal static bool IsEnabled(string feature) { return !DisabledFeatures.Contains(feature); } internal static void Fail(string feature, Exception error) { if (DisabledFeatures.Add(feature)) { ManualLogSource log = PlantationsPlugin.Log; if (log != null) { log.LogError((object)$"[{feature}] disabled after an unexpected error: {error}"); } } } internal static void ApplyAll(Harmony harmony) { Type[] array = new Type[15] { typeof(Code_PlantationsRemoval), typeof(Code_PlantationsHarvest), typeof(Code_PlantationsAreaHarvest), typeof(Code_PlantationsAudioMixer), typeof(Code_PlantationsGrowth), typeof(Code_PlantationsTimers), typeof(Code_PlantationsGridRegistration), typeof(Code_PlantationsGridControls), typeof(Code_PlantationsGridHints), typeof(Code_PlantationsGridCost), typeof(Code_PlantationsGridPlacement.PlayerSetupPlacementGhost), typeof(Code_PlantationsGridPlacement.PlayerUpdatePlacementGhost), typeof(Code_PlantationsGridPlacement.PlayerTryPlacePiece), typeof(Code_PlantationsGridPlacement.PlayerPlacePiece), typeof(RegisterClientRPCPatch) }; Type[] array2 = array; foreach (Type type in array2) { if (PlantationsGridContext.config != null || (!type.Name.StartsWith("Code_PlantationsGrid", StringComparison.Ordinal) && !(type.DeclaringType == typeof(Code_PlantationsGridPlacement)))) { try { harmony.CreateClassProcessor(type).Patch(); } catch (Exception error) { Fail(type.Name, error); } } } } } internal sealed class PlantDefinition { public string PiecePrefab; public string SeedlingPrefab; public string VanillaPickable; public string NormalDropPrefab; public string SeedPrefab; public Func<int> DropAmount; public Func<int> SeedAmount; public Func<float> SeedChance; public Func<float> RespawnMinutes; public Func<bool> VanillaSeedDropEnabled; public int PieceHash; public int SeedlingHash; public int VanillaHash; internal DropTable CachedSeedTable; internal bool SeedTableBuilt; } internal static class PlantDefinitions { private const string CloneSuffix = "(Clone)"; private const int NameCacheLimit = 1024; internal static readonly PlantDefinition[] All; private static readonly Dictionary<int, PlantDefinition> ByPieceHash; private static readonly Dictionary<int, PlantDefinition> ByVanillaHash; private static readonly Dictionary<string, int> NameHashCache; private static ConfigFile _configuration; static PlantDefinitions() { All = new PlantDefinition[9] { Def("RD_Dandelion", "Pickable_Dandelion", "Dandelion", "RD_seed_dandelion", () => PlantationsPlugin.CE_RD_Dandelion_DropAmount.Value, () => PlantationsPlugin.CE_RD_Dandelion_ExtraDropAmount.Value, () => PlantationsPlugin.CE_RD_Dandelion_ExtraDropChance.Value, () => PlantationsPlugin.CE_RD_Dandelion_RespawnTimeMinutes.Value, () => PlantationsPlugin.CE_RD_Dandelion_VanillaSeedDropEnabled.Value), Def("RD_Mushroom", "Pickable_Mushroom", "Mushroom", "RD_red_spore", () => PlantationsPlugin.CE_RD_Mushroom_DropAmount.Value, () => PlantationsPlugin.CE_RD_Mushroom_ExtraDropAmount.Value, () => PlantationsPlugin.CE_RD_Mushroom_ExtraDropChance.Value, () => PlantationsPlugin.CE_RD_Mushroom_RespawnTimeMinutes.Value, () => PlantationsPlugin.CE_RD_Mushroom_VanillaSeedDropEnabled.Value), Def("RD_Mushroom_yellow", "Pickable_Mushroom_yellow", "MushroomYellow", "RD_yellow_spore", () => PlantationsPlugin.CE_RD_Mushroom_yellow_DropAmount.Value, () => PlantationsPlugin.CE_RD_Mushroom_yellow_ExtraDropAmount.Value, () => PlantationsPlugin.CE_RD_Mushroom_yellow_ExtraDropChance.Value, () => PlantationsPlugin.CE_RD_Mushroom_yellow_RespawnTimeMinutes.Value, () => PlantationsPlugin.CE_RD_Mushroom_yellow_VanillaSeedDropEnabled.Value), Def("RD_RaspberryBush", "RaspberryBush", "Raspberry", "RD_seed_raspberry", () => PlantationsPlugin.CE_RD_RaspberryBush_DropAmount.Value, () => PlantationsPlugin.CE_RD_RaspberryBush_ExtraDropAmount.Value, () => PlantationsPlugin.CE_RD_RaspberryBush_ExtraDropChance.Value, () => PlantationsPlugin.CE_RD_RaspberryBush_RespawnTimeMinutes.Value, () => PlantationsPlugin.CE_RD_RaspberryBush_VanillaSeedDropEnabled.Value), Def("RD_BlueberryBush", "BlueberryBush", "Blueberries", "RD_seed_blueberry", () => PlantationsPlugin.CE_RD_BlueberryBush_DropAmount.Value, () => PlantationsPlugin.CE_RD_BlueberryBush_ExtraDropAmount.Value, () => PlantationsPlugin.CE_RD_BlueberryBush_ExtraDropChance.Value, () => PlantationsPlugin.CE_RD_BlueberryBush_RespawnTimeMinutes.Value, () => PlantationsPlugin.CE_RD_BlueberryBush_VanillaSeedDropEnabled.Value), Def("RD_thistle", "Pickable_Thistle", "Thistle", "RD_seed_thistle", () => PlantationsPlugin.CE_RD_thistle_DropAmount.Value, () => PlantationsPlugin.CE_RD_thistle_ExtraDropAmount.Value, () => PlantationsPlugin.CE_RD_thistle_ExtraDropChance.Value, () => PlantationsPlugin.CE_RD_thistle_RespawnTimeMinutes.Value, () => PlantationsPlugin.CE_RD_thistle_VanillaSeedDropEnabled.Value), Def("RD_CloudberryBush", "CloudberryBush", "Cloudberry", "RD_seed_cloudberry", () => PlantationsPlugin.CE_RD_CloudberryBush_DropAmount.Value, () => PlantationsPlugin.CE_RD_CloudberryBush_ExtraDropAmount.Value, () => PlantationsPlugin.CE_RD_CloudberryBush_ExtraDropChance.Value, () => PlantationsPlugin.CE_RD_CloudberryBush_RespawnTimeMinutes.Value, () => PlantationsPlugin.CE_RD_CloudberryBush_VanillaSeedDropEnabled.Value), Def("RD_MushroomSmokePuff", "Pickable_SmokePuff", "MushroomSmokePuff", "RD_seed_smokepuff", () => PlantationsPlugin.CE_RD_MushroomSmokePuff_DropAmount.Value, () => PlantationsPlugin.CE_RD_MushroomSmokePuff_ExtraDropAmount.Value, () => PlantationsPlugin.CE_RD_MushroomSmokePuff_ExtraDropChance.Value, () => PlantationsPlugin.CE_RD_MushroomSmokePuff_RespawnTimeMinutes.Value, () => PlantationsPlugin.CE_RD_MushroomSmokePuff_VanillaSeedDropEnabled.Value), Def("RD_Fiddlehead", "Pickable_Fiddlehead", "Fiddleheadfern", "RD_seed_fiddlehead", () => PlantationsPlugin.CE_RD_Fiddlehead_DropAmount.Value, () => PlantationsPlugin.CE_RD_Fiddlehead_ExtraDropAmount.Value, () => PlantationsPlugin.CE_RD_Fiddlehead_ExtraDropChance.Value, () => PlantationsPlugin.CE_RD_Fiddlehead_RespawnTimeMinutes.Value, () => PlantationsPlugin.CE_RD_Fiddlehead_VanillaSeedDropEnabled.Value) }; ByPieceHash = new Dictionary<int, PlantDefinition>(); ByVanillaHash = new Dictionary<int, PlantDefinition>(); NameHashCache = new Dictionary<string, int>(64, StringComparer.Ordinal); PlantDefinition[] all = All; foreach (PlantDefinition plantDefinition in all) { plantDefinition.PieceHash = StringExtensionMethods.GetStableHashCode(plantDefinition.PiecePrefab); plantDefinition.SeedlingHash = StringExtensionMethods.GetStableHashCode(plantDefinition.SeedlingPrefab); plantDefinition.VanillaHash = StringExtensionMethods.GetStableHashCode(plantDefinition.VanillaPickable); ByPieceHash[plantDefinition.PieceHash] = plantDefinition; ByPieceHash[plantDefinition.SeedlingHash] = plantDefinition; ByVanillaHash[plantDefinition.VanillaHash] = plantDefinition; } } private static PlantDefinition Def(string piece, string vanilla, string drop, string seed, Func<int> dropAmount, Func<int> seedAmount, Func<float> seedChance, Func<float> respawn, Func<bool> vanillaSeed) { return new PlantDefinition { PiecePrefab = piece, SeedlingPrefab = piece + "_seedling", VanillaPickable = vanilla, NormalDropPrefab = drop, SeedPrefab = seed, DropAmount = dropAmount, SeedAmount = seedAmount, SeedChance = seedChance, RespawnMinutes = respawn, VanillaSeedDropEnabled = vanillaSeed }; } internal static void Init(ConfigFile config) { Shutdown(); _configuration = config; config.SettingChanged += OnConfigurationChanged; } private static void OnConfigurationChanged(object sender, SettingChangedEventArgs args) { InvalidateCaches(); PlantationsPlugin.Instance.QueuePlantRefresh(); } internal static void Shutdown() { if (_configuration != null) { _configuration.SettingChanged -= OnConfigurationChanged; } _configuration = null; InvalidateCaches(); NameHashCache.Clear(); } internal static void InvalidateCaches() { PlantDefinition[] all = All; foreach (PlantDefinition plantDefinition in all) { plantDefinition.CachedSeedTable = null; plantDefinition.SeedTableBuilt = false; } } internal static int GetPrefabHash(GameObject obj) { if (!Object.op_Implicit((Object)(object)obj)) { return 0; } ZNetView component = obj.GetComponent<ZNetView>(); ZDO val = (Object.op_Implicit((Object)(object)component) ? component.GetZDO() : null); if (val != null) { return val.GetPrefab(); } return GetNameHash(((Object)obj).name); } internal static int GetNameHash(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); if (NameHashCache.Count >= 1024) { NameHashCache.Clear(); } NameHashCache[name] = value; return value; } internal static bool IsPieceHash(int hash) { return ByPieceHash.ContainsKey(hash); } internal static bool TryGetByPieceHash(int hash, out PlantDefinition def) { return ByPieceHash.TryGetValue(hash, out def); } internal static bool TryGetPiece(GameObject obj, out PlantDefinition def) { def = null; return Object.op_Implicit((Object)(object)obj) && ByPieceHash.TryGetValue(GetPrefabHash(obj), out def); } internal static bool TryGetVanilla(GameObject obj, out PlantDefinition def) { def = null; return Object.op_Implicit((Object)(object)obj) && ByVanillaHash.TryGetValue(GetPrefabHash(obj), out def); } internal 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; } internal static DropTable GetSeedTable(PlantDefinition def) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown if (def.SeedTableBuilt) { return def.CachedSeedTable; } int num = def.SeedAmount(); float num2 = Mathf.Clamp01(def.SeedChance()); GameObject prefab = GetPrefab(def.SeedPrefab); if (num <= 0 || num2 <= 0f) { def.CachedSeedTable = null; def.SeedTableBuilt = true; return null; } if (!Object.op_Implicit((Object)(object)prefab)) { return null; } def.CachedSeedTable = 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 } } }; def.SeedTableBuilt = true; return def.CachedSeedTable; } } [HarmonyPatch] internal static class Code_PlantationsGrowth { private const string Feature = "Code_PlantationsGrowth"; private static bool Prepare() { return PatchSafety.IsEnabled("Code_PlantationsGrowth"); } [HarmonyPatch(typeof(Plant), "GetGrowTime")] [HarmonyPrefix] private static bool Plant_GetGrowTime_Prefix(Plant __instance, ref float __result) { if (!PatchSafety.IsEnabled("Code_PlantationsGrowth") || !PlantDefinitions.TryGetPiece(((Component)__instance).gameObject, out var def) || PlantDefinitions.GetPrefabHash(((Component)__instance).gameObject) != def.SeedlingHash) { return true; } __result = Code_PlantationsHarvest.SanitizeRespawnMinutes(def.RespawnMinutes()) * 60f; return false; } [HarmonyPostfix] [HarmonyPatch(typeof(Piece), "Awake")] private static void Piece_Awake_Postfix(Piece __instance) { if (!PatchSafety.IsEnabled("Code_PlantationsGrowth")) { return; } try { ApplyResources(__instance); } catch (Exception error) { PatchSafety.Fail("Code_PlantationsGrowth", error); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void ApplyResources(Piece piece) { int prefabHash = PlantDefinitions.GetPrefabHash(((Component)piece).gameObject); if (PlantDefinitions.TryGetByPieceHash(prefabHash, out var def) && prefabHash == def.PieceHash) { GameObject prefab = PlantDefinitions.GetPrefab(def.SeedlingPrefab); Piece val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<Piece>() : null); if (Object.op_Implicit((Object)(object)val)) { piece.m_resources = val.m_resources; } } } [HarmonyPatch(typeof(Plant), "Grow")] [HarmonyPrefix] private static void Plant_Grow_Prefix(Plant __instance, out (long Creator, int PlatformIndex) __state) { __state = (Creator: 0L, PlatformIndex: -1); if (!PatchSafety.IsEnabled("Code_PlantationsGrowth")) { return; } try { __state = GetCreator(__instance); } catch (Exception error) { PatchSafety.Fail("Code_PlantationsGrowth", error); } } [MethodImpl(MethodImplOptions.NoInlining)] private static (long, int) GetCreator(Plant plant) { int prefabHash = PlantDefinitions.GetPrefabHash(((Component)plant).gameObject); if (!PlantDefinitions.TryGetByPieceHash(prefabHash, out var def) || prefabHash != def.SeedlingHash) { return (0L, -1); } Piece component = ((Component)plant).GetComponent<Piece>(); return Object.op_Implicit((Object)(object)component) ? (component.GetCreator(), component.GetCreatorPlatformUserIdIndex()) : (0L, -1); } [HarmonyPostfix] [HarmonyPatch(typeof(Plant), "Grow")] private static void Plant_Grow_Postfix(GameObject __result, (long Creator, int PlatformIndex) __state) { if (!PatchSafety.IsEnabled("Code_PlantationsGrowth")) { return; } try { TransferCreator(__result, __state); } catch (Exception error) { PatchSafety.Fail("Code_PlantationsGrowth", error); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void TransferCreator(GameObject grown, (long Creator, int PlatformIndex) creator) { if (!Object.op_Implicit((Object)(object)grown) || creator.Creator == 0) { return; } int prefabHash = PlantDefinitions.GetPrefabHash(grown); if (PlantDefinitions.TryGetByPieceHash(prefabHash, out var def) && prefabHash == def.PieceHash) { Piece component = grown.GetComponent<Piece>(); ZNetView val = (Object.op_Implicit((Object)(object)component) ? component.m_nview : null); if (Object.op_Implicit((Object)(object)val) && val.IsValid() && val.IsOwner() && component.GetCreator() == 0) { ZDO zDO = val.GetZDO(); zDO.Set(ZDOVars.s_creator, creator.Creator); zDO.Set(ZDOVars.s_creatorIndex, creator.PlatformIndex, false); (component.m_creator, component.m_creatorPlatformUserIDIndex) = creator; } } } } public static class EffectRegistry { public static void Register() { PrefabManager.RegisterPrefab("rd_plantations", "vfx_Place_smallitem_rd_plantations"); PrefabManager.RegisterPrefab("rd_plantations", "sfx_build_cultivator_rd_plantations"); PrefabManager.RegisterPrefab("rd_plantations", "vfx_bush_destroyed_rd_plantations"); PrefabManager.RegisterPrefab("rd_plantations", "vfx_bush_leaf_puff_rd_plantations"); PrefabManager.RegisterPrefab("rd_plantations", "sfx_bush_hit_rd_plantations"); PrefabManager.RegisterPrefab("rd_plantations", "sfx_pickable_pick_rd_plantations"); PrefabManager.RegisterPrefab("rd_plantations", "vfx_pickable_pick_rd_plantations"); } } [BepInPlugin("radamanto.Plantations", "Plantations", "1.0.4")] [<751c224d-bfbf-4350-9e31-32d445024a3b>NullableContext(1)] [<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>Nullable(0)] [BepInIncompatibility("advize.PlantEasily")] public class PlantationsPlugin : BaseUnityPlugin { [<751c224d-bfbf-4350-9e31-32d445024a3b>NullableContext(0)] private class ConfigurationManagerAttributes { public bool? Browsable = false; } internal const string ModGUID = "radamanto.Plantations"; internal const string ModName = "Plantations"; internal const string ModVersion = "1.0.4"; [<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>Nullable(2)] internal static ManualLogSource Log; internal static PlantationsPlugin Instance; private Harmony _harmony = null; private bool _plantRefreshScheduled; internal const float MinRespawnMinutes = 1f; internal const float MaxRespawnMinutes = 100000f; internal const float DefaultRespawnMinutes = 60f; 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; [<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>Nullable(2)] internal static ConfigSync ConfigSync; [<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>Nullable(2)] private static ConfigEntry<bool> _serverConfigLocked; [<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>Nullable(2)] private FileSystemWatcher _configWatcher; private long _lastCfgWrite; private bool _reloadScheduled; private bool _watcherReady; private void Awake() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Invalid comparison between Unknown and I4 Instance = this; BuildPiece._plugin = (BaseUnityPlugin)(object)this; Localizer.Load(); Log = ((BaseUnityPlugin)this).Logger; _harmony = new Harmony("radamanto.Plantations"); bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { SetupServerSync(); BindConfiguration(); SeedRegistry.Register(); PlantRegistry.Register(); EffectRegistry.Register(); PlantDefinitions.Init(((BaseUnityPlugin)this).Config); if ((int)SystemInfo.graphicsDeviceType != 4) { PlantationsGridContext.ModLogger = Log; PlantationsGridContext.config = new PlantationsGridConfig(((BaseUnityPlugin)this).Config); } Code_PlantationsAreaHarvest.Initialize(((BaseUnityPlugin)this).Config); PatchSafety.ApplyAll(_harmony); Code_PlantationsAudioMixer.Initialize(); } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } ((BaseUnityPlugin)this).Config.Save(); SetupConfigWatcher(); } internal void QueuePlantRefresh() { if (!_plantRefreshScheduled) { _plantRefreshScheduled = true; ((MonoBehaviour)this).Invoke("RefreshPlants", 0f); } } private void RefreshPlants() { _plantRefreshScheduled = false; Code_PlantationsHarvest.RefreshLoadedPlants(); } private void OnDestroy() { _watcherReady = false; if (_configWatcher != null) { _configWatcher.EnableRaisingEvents = false; _configWatcher.Dispose(); _configWatcher = null; } _reloadScheduled = false; ((MonoBehaviour)this).CancelInvoke(); PlantDefinitions.Shutdown(); Code_PlantationsHarvest.ClearLoadedPlants(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void BindConfiguration() { 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 = CfgRange("02 - Dandelion", "02.01 - Dandelion Drop Amount", 3, "Dandelion drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); CE_RD_Dandelion_ExtraDropAmount = CfgRange("02 - Dandelion", "02.02 - Dandelion Seed Drop Amount", 1, "Dandelion seed drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000)); CE_RD_Dandelion_ExtraDropChance = CfgRange("02 - Dandelion", "02.03 - Dandelion Seed Drop Chance", 0.05f, "Chance for Dandelion seed to drop. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); 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 = CfgRespawn("02 - Dandelion", "02.05 - Dandelion Respawn Time Minutes", "Dandelion respawn time in minutes."); CE_RD_Mushroom_DropAmount = CfgRange("03 - Mushroom", "03.01 - Mushroom Drop Amount", 3, "Mushroom drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); CE_RD_Mushroom_ExtraDropAmount = CfgRange("03 - Mushroom", "03.02 - Red Mushroom Spore Drop Amount", 1, "Red Mushroom spore drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000)); CE_RD_Mushroom_ExtraDropChance = CfgRange("03 - Mushroom", "03.03 - Red Mushroom Spore Drop Chance", 0.05f, "Chance for Red Mushroom spore to drop. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); 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 = CfgRespawn("03 - Mushroom", "03.05 - Mushroom Respawn Time Minutes", "Mushroom respawn time in minutes."); CE_RD_Mushroom_yellow_DropAmount = CfgRange("04 - Yellow Mushroom", "04.01 - Yellow Mushroom Drop Amount", 3, "Yellow Mushroom drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); CE_RD_Mushroom_yellow_ExtraDropAmount = CfgRange("04 - Yellow Mushroom", "04.02 - Yellow Mushroom Spore Drop Amount", 1, "Yellow Mushroom spore drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000)); CE_RD_Mushroom_yellow_ExtraDropChance = CfgRange("04 - Yellow Mushroom", "04.03 - Yellow Mushroom Spore Drop Chance", 0.05f, "Chance for Yellow Mushroom spore to drop. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); 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 = CfgRespawn("04 - Yellow Mushroom", "04.05 - Yellow Mushroom Respawn Time Minutes", "Yellow Mushroom respawn time in minutes."); CE_RD_RaspberryBush_DropAmount = CfgRange("05 - Raspberry", "05.01 - Raspberry Drop Amount", 3, "Raspberry drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); CE_RD_RaspberryBush_ExtraDropAmount = CfgRange("05 - Raspberry", "05.02 - Raspberry Seed Drop Amount", 1, "Raspberry seed drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000)); CE_RD_RaspberryBush_ExtraDropChance = CfgRange("05 - Raspberry", "05.03 - Raspberry Seed Drop Chance", 0.05f, "Chance for Raspberry seed to drop. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); 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 = CfgRespawn("05 - Raspberry", "05.05 - Raspberry Respawn Time Minutes", "Raspberry respawn time in minutes."); CE_RD_BlueberryBush_DropAmount = CfgRange("06 - Blueberry", "06.01 - Blueberry Drop Amount", 3, "Blueberry drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); CE_RD_BlueberryBush_ExtraDropAmount = CfgRange("06 - Blueberry", "06.02 - Blueberry Seed Drop Amount", 1, "Blueberry seed drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000)); CE_RD_BlueberryBush_ExtraDropChance = CfgRange("06 - Blueberry", "06.03 - Blueberry Seed Drop Chance", 0.05f, "Chance for Blueberry seed to drop. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); 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 = CfgRespawn("06 - Blueberry", "06.05 - Blueberry Respawn Time Minutes", "Blueberry respawn time in minutes."); CE_RD_thistle_DropAmount = CfgRange("07 - Thistle", "07.01 - Thistle Drop Amount", 3, "Thistle drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); CE_RD_thistle_ExtraDropAmount = CfgRange("07 - Thistle", "07.02 - Thistle Seed Drop Amount", 1, "Thistle seed drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000)); CE_RD_thistle_ExtraDropChance = CfgRange("07 - Thistle", "07.03 - Thistle Seed Drop Chance", 0.05f, "Chance for Thistle seed to drop. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); 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 = CfgRespawn("07 - Thistle", "07.05 - Thistle Respawn Time Minutes", "Thistle respawn time in minutes."); CE_RD_CloudberryBush_DropAmount = CfgRange("08 - Cloudberry", "08.01 - Cloudberry Drop Amount", 3, "Cloudberry drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); CE_RD_CloudberryBush_ExtraDropAmount = CfgRange("08 - Cloudberry", "08.02 - Cloudberry Seed Drop Amount", 1, "Cloudberry seed drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000)); CE_RD_CloudberryBush_ExtraDropChance = CfgRange("08 - Cloudberry", "08.03 - Cloudberry Seed Drop Chance", 0.05f, "Chance for Cloudberry seed to drop. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); 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 = CfgRespawn("08 - Cloudberry", "08.05 - Cloudberry Respawn Time Minutes", "Cloudberry respawn time in minutes."); CE_RD_MushroomSmokePuff_DropAmount = CfgRange("09 - Smoke Puff", "09.01 - Smoke Puff Drop Amount", 3, "Smoke Puff drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); CE_RD_MushroomSmokePuff_ExtraDropAmount = CfgRange("09 - Smoke Puff", "09.02 - Smoke Puff Seed Drop Amount", 1, "Smoke Puff seed drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000)); CE_RD_MushroomSmokePuff_ExtraDropChance = CfgRange("09 - Smoke Puff", "09.03 - Smoke Puff Seed Drop Chance", 0.05f, "Chance for Smoke Puff seed to drop. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); 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 = CfgRespawn("09 - Smoke Puff", "09.05 - Smoke Puff Respawn Time Minutes", "Smoke Puff respawn time in minutes."); CE_RD_Fiddlehead_DropAmount = CfgRange("10 - Fiddlehead", "10.01 - Fiddlehead Drop Amount", 3, "Fiddlehead drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); CE_RD_Fiddlehead_ExtraDropAmount = CfgRange("10 - Fiddlehead", "10.02 - Fiddlehead Seed Drop Amount", 1, "Fiddlehead seed drop amount.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000)); CE_RD_Fiddlehead_ExtraDropChance = CfgRange("10 - Fiddlehead", "10.03 - Fiddlehead Seed Drop Chance", 0.05f, "Chance for Fiddlehead seed to drop. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); 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 = CfgRespawn("10 - Fiddlehead", "10.05 - Fiddlehead Respawn Time Minutes", "Fiddlehead respawn time in minutes."); } private ConfigEntry<T> CfgRange<[<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>Nullable(2)] T>(string section, string key, T defaultValue, string description, AcceptableValueBase range) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return BindConfig(section, key, defaultValue, new ConfigDescription(description, range, Array.Empty<object>())); } private ConfigEntry<float> CfgRespawn(string section, string key, string description) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown return BindConfig(section, key, 60f, new ConfigDescription($"{description} Also controls initial seedling growth time. Minimum {1f} (0 would destroy the plant when harvested).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100000f), Array.Empty<object>())); } private void SetupServerSync() { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown 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); } private ConfigEntry<T> BindConfig<[<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>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); if (ConfigSync == null) { throw new InvalidOperationException("ServerSync has not been initialized."); } ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting; return val2; } private ConfigEntry<T> BindConfig<[<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>Nullable(2)] T>(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return BindConfig(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting); } protected ConfigEntry<T> Cfg<[<ad47d627-eefa-4fa9-aeb5-d2cdcce92dc3>Nullable(2)] T>(string section, string key, T defaultValue, string description, bool synced = true) { return BindConfig(section, key, defaultValue, description, synced); } private void SetupConfigWatcher() { try { _watcherReady = false; _configWatcher?.Dispose(); _configWatcher = new FileSystemWatcher(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath)) { IncludeSubdirectories = false, NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite), SynchronizingObject = ThreadingHelper.SynchronizingObject }; _configWatcher.Changed += OnConfigFileChanged; _configWatcher.Created += OnConfigFileChanged; _configWatcher.Renamed += [<751c224d-bfbf-4350-9e31-32d445024a3b>NullableContext(0)] (object _, RenamedEventArgs args) => { OnConfigFileChanged(_, args); }; _configWatcher.Error += [<751c224d-bfbf-4350-9e31-32d445024a3b>NullableContext(0)] (object _, ErrorEventArgs args) => { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Configuration watcher failed: {args.GetException()}"); }; _watcherReady = true; _configWatcher.EnableRaisingEvents = true; } catch (Exception arg) { _watcherReady = false; _configWatcher?.Dispose(); _configWatcher = null; ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Automatic configuration reload is unavailable: {arg}"); } } private void OnConfigFileChanged(object sender, FileSystemEventArgs args) { if (_watcherReady) { _lastCfgWrite = Stopwatch.GetTimestamp(); if (!_reloadScheduled) { _reloadScheduled = true; ((MonoBehaviour)this).StartCoroutine(ReloadConfigAfterQuietPeriod()); } } } private IEnumerator ReloadConfigAfterQuietPeriod() { try { for (int attempt = 0; attempt < 3; attempt++) { if (!_watcherReady) { break; } while (_watcherReady && (double)(Stopwatch.GetTimestamp() - _lastCfgWrite) / (double)Stopwatch.Frequency < 0.75) { yield return (object)new WaitForSecondsRealtime(0.75f); } if (!_watcherReady || ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())) { break; } bool saveOnSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; bool retry = false; try { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; ((BaseUnityPlugin)this).Config.Reload(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Configuration reloaded."); } catch (IOException ex) { IOException error = ex; retry = true; if (attempt == 2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Configuration could not be read after 3 attempts: {error}"); } } catch (Exception ex2) { Exception error2 = ex2; ((BaseUnityPlugin)this).Logger.LogError((object)$"Configuration reload failed: {error2}"); } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnSet; } if (!retry) { break; } _lastCfgWrite = Stopwatch.GetTimestamp(); } } finally { _reloadScheduled = false; } } } internal static class PlantationsGridContext { internal static readonly Dictionary<string, GameObject> PrefabRefs = new Dictionary<string, GameObject>(); internal static ManualLogSource ModLogger = new ManualLogSource("Plantations Grid"); internal static PlantationsGridConfig config; internal static List<GridPickableDefinition> PickableRefs = new List<GridPickableDefinition>(); internal static void Dbgl(string message, bool forceLog = false, LogLevel level = (LogLevel)16) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (forceLog || config.EnableDebugMessages) { ModLogger.Log(level, (object)message); } } } internal static class PlantationsGridRules { private static readonly Dictionary<int, float> AdultColliderRadii = new Dictionary<int, float>(); internal static bool HoldingCultivator { get { Player localPlayer = Player.m_localPlayer; return ((localPlayer == null) ? null : ((Humanoid)localPlayer).GetRightItem()?.m_shared.m_name) == "$item_cultivator"; } } internal static bool IsPlantOrPickable(GameObject go) { if (!Object.op_Implicit((Object)(object)go.GetComponent<Plant>())) { return Object.op_Implicit((Object)(object)go.GetComponent<Pickable>()); } return true; } internal static bool HasGrowSpace(Plant plant, Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Physics.OverlapSphere(position, plant.m_growRadius, Plant.m_spaceMask).Length == 0; } internal static bool PositionHasCollisions(Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //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) return Physics.CheckCapsule(position, position + Vector3.up * 0.1f, Mathf.Epsilon, PlantationsGridCollisions.CollisionMask); } internal static float GetPieceSpacing(GameObject go) { float num = 0f; bool flag = false; Plant component = go.GetComponent<Plant>(); if (Object.op_Implicit((Object)(object)component)) { GameObject[] grownPrefabs = component.m_grownPrefabs; List<GameObject> list = new List<GameObject>(1 + grownPrefabs.Length); list.Add(go); list.AddRange(grownPrefabs); List<GameObject> list2 = list; flag = list2.Any((GameObject x) => Object.op_Implicit((Object)(object)x.GetComponent<TreeBase>())); if (PlantationsGridContext.config.MinimizeGridSpacing && !flag) { for (int num2 = 0; num2 < list2.Count; num2++) { CapsuleCollider[] componentsInChildren = list2[num2].GetComponentsInChildren<CapsuleCollider>(); CapsuleCollider[] array = componentsInChildren; foreach (CapsuleCollider val in array) { num = Mathf.Max(num, val.radius); } } } num += (flag ? PlantationsGridContext.config.ExtraSaplingSpacing : PlantationsGridContext.config.ExtraCropSpacing); } float num4 = (flag ? (component.m_growRadius * 2.2f) : ((component?.m_growRadius * (PlantationsGridContext.config.MinimizeGridSpacing ? 1.1f : 2f)) ?? PickableSnapRadius(go.GetComponent<Piece>()))) + num; if (Object.op_Implicit((Object)(object)component) && PlantDefinitions.TryGetPiece(go, out var def)) { float adultColliderRadius = GetAdultColliderRadius(component, def); float radius; float num5 = (PlantationsGridContext.config.TryGetScatterRadius(out radius) ? Mathf.Abs(radius) : 0f); float num6 = component.m_growRadius + Mathf.Max(component.m_growRadius, adultColliderRadius) + 0.1f + num5 * 2f; num4 = Mathf.Max(num4, num6 + PlantationsGridContext.config.ExtraCropSpacing); } return num4; } private static float GetAdultColliderRadius(Plant plant, PlantDefinition definition) { //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) if (AdultColliderRadii.TryGetValue(definition.PieceHash, out var value)) { return value * Mathf.Max(plant.m_minScale, plant.m_maxScale); } value = 0f; GameObject[] grownPrefabs = plant.m_grownPrefabs; foreach (GameObject val in grownPrefabs) { if (!Object.op_Implicit((Object)(object)val)) { continue; } Collider[] componentsInChildren = val.GetComponentsInChildren<Collider>(true); foreach (Collider val2 in componentsInChildren) { if (!val2.enabled || val2.isTrigger || ((Component)val2).gameObject.layer == LayerMask.NameToLayer("viewblock")) { continue; } Collider val3 = val2; Collider val4 = val3; SphereCollider val5 = (SphereCollider)(object)((val4 is SphereCollider) ? val4 : null); Vector3 center; Vector3 val8; if (val5 == null) { CapsuleCollider val6 = (CapsuleCollider)(object)((val4 is CapsuleCollider) ? val4 : null); if (val6 == null) { BoxCollider val7 = (BoxCollider)(object)((val4 is BoxCollider) ? val4 : null); if (val7 == null) { continue; } center = val7.center; val8 = val7.size * 0.5f; } else { center = val6.center; val8 = Vector3.one * val6.radius; ((Vector3)(ref val8))[val6.direction] = Mathf.Max(val6.height * 0.5f, val6.radius); } } else { center = val5.center; val8 = Vector3.one * val5.radius; } for (int k = 0; k < 8; k++) { Vector3 val9 = center + Vector3.Scale(val8, new Vector3(((k & 1) == 0) ? (-1f) : 1f, ((k & 2) == 0) ? (-1f) : 1f, ((k & 4) == 0) ? (-1f) : 1f)); val9 = val.transform.InverseTransformPoint(((Component)val2).transform.TransformPoint(val9)); float num = value; Vector2 val10 = new Vector2(val9.x, val9.z); value = Mathf.Max(num, ((Vector2)(ref val10)).magnitude); } } } AdultColliderRadii[definition.PieceHash] = value; return value * Mathf.Max(plant.m_minScale, plant.m_maxScale); } private static float PickableSnapRadius(Piece p) { if (p == null || !(p.m_harvestRadius > 0f)) { return PlantationsGridContext.config.DefaultGridSpacing + PlantationsGridContext.config.ExtraCropSpacing; } return p.m_harvestRadius + PlantationsGridContext.config.ExtraCropSpacing; } } internal enum GridAlignmentMode { Intelligent, Legacy } internal enum GridPlacementStatus { Healthy, LackResources, NotCultivated, WrongBiome, NoSpace, NoSun, Invalid, NoAttachPiece, TooHot, TooCold } internal sealed class PlantationsGridConfig { private readonly ConfigFile Config; private readonly ConfigEntry<KeyboardShortcut> enableModKey; private readonly ConfigEntry<KeyboardShortcut> enableSnappingKey; private readonly ConfigEntry<KeyboardShortcut> cycleSizeKey; private readonly ConfigEntry<bool> modActive; private readonly ConfigEntry<bool> snapActive; private readonly ConfigEntry<bool> useStamina; private readonly ConfigEntry<bool> useDurability; private readonly ConfigEntry<bool> showCost; private readonly ConfigEntry<bool> showHUDKeyHints; private readonly ConfigEntry<bool> showGridDirections; private readonly ConfigEntry<float> extraSpacing; private int size = 3; internal KeyboardShortcut EnableModKey => enableModKey.Value; internal KeyboardShortcut EnableSnappingKey => enableSnappingKey.Value; internal KeyboardShortcut CycleSizeKey => cycleSizeKey.Value; internal KeyCode GamepadModifierKey => (KeyCode)334; internal bool ModActive { get { return modActive.Value; } set { modActive.Value = value; } } internal bool SnapActive { get { return snapActive.Value; } set { snapActive.Value = value; } } internal int Rows => size; internal int Columns => size; internal bool UseStamina => useStamina.Value; internal bool UseDurability => useDurability.Value; internal bool ShowCost => showCost.Value; internal bool ShowHUDKeyHints => showHUDKeyHints.Value; internal bool ShowGridDirections => showGridDirections.Value; internal float ExtraCropSpacing => extraSpacing.Value; internal float ExtraSaplingSpacing => extraSpacing.Value; internal bool PreventPartialPlanting => false; internal bool PreventInvalidPlanting => true; internal bool RandomizeRotation => true; internal bool EnableDebugMessages => false; internal bool GloballyAlignGridDirections => true; internal bool MinimizeGridSpacing => false; internal GridAlignmentMode GridAlignmentMode => GridAlignmentMode.Intelligent; internal bool ForceAltPlacement => false; internal bool PreferCardinalSnapping => false; internal int MaxConcurrentPlacements => 25; internal int GhostUpdateBatchSize => 20; internal int BulkPlantingBatchSize => 2; internal bool PreventOverlappingPlacements => true; internal float DefaultGridSpacing => 1f; internal bool ShowGhostsDuringPlacement => true; internal bool ShowSnapDirection => ShowGridDirections; internal bool HighlightRootPlacementGhost => true; internal Color RootGhostHighlightColor => Color32.op_Implicit(new Color32((byte)166, (byte)230, (byte)122, byte.MaxValue)); internal Color RowStartColor => Color32.op_Implicit(new Color32((byte)230, (byte)166, (byte)47, byte.MaxValue)); internal Color RowEndColor => Color32.op_Implicit(new Color32(byte.MaxValue, (byte)225, (byte)145, byte.MaxValue)); internal Color ColumnStartColor => Color32.op_Implicit(new Color32((byte)30, (byte)179, (byte)159, byte.MaxValue)); internal Color ColumnEndColor => Color32.op_Implicit(new Color32((byte)146, (byte)240, (byte)219, byte.MaxValue)); internal Color SnapStartColor => Color32.op_Implicit(new Color32((byte)142, (byte)97, (byte)212, byte.MaxValue)); internal Color SnapEndColor => Color32.op_Implicit(new Color32((byte)213, (byte)180, (byte)250, byte.MaxValue)); internal PlantationsGridConfig(ConfigFile configFile) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown Config = configFile; bool saveOnConfigSet = Config.SaveOnConfigSet; Config.SaveOnConfigSet = false; try { modActive = Config.Bind<bool>("11 - Planting Grid", "11.01 - Enabled", true, "Enable the planting grid. F8 toggles it while using the cultivator."); enableModKey = Config.Bind<KeyboardShortcut>("12 - Grid Controls", "12.01 - Toggle Key", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Toggle the planting grid while using the cultivator. Set to None to disable this shortcut."); cycleSizeKey = Config.Bind<KeyboardShortcut>("12 - Grid Controls", "12.02 - Cycle Size Key", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "Cycle square grid sizes: 2x2, 3x3, 4x4, 5x5. Initial size: 3x3 each session. Gamepad: LB + D-pad Up. Set to None to disable this keyboard shortcut."); snapActive = Config.Bind<bool>("11 - Planting Grid", "11.05 - Snapping", true, "Snap the grid to existing plants."); enableSnappingKey = Config.Bind<KeyboardShortcut>("12 - Grid Controls", "EnableSnappingKey", new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>()), "Toggle grid snapping while using the cultivator. Set to None to disable this shortcut."); useStamina = Config.Bind<bool>("14 - Grid Placement", "UseStamina", true, "Consume the vanilla build stamina cost for each additional plant. The first plant keeps its vanilla cost."); useDurability = Config.Bind<bool>("14 - Grid Placement", "UseDurability", true, "Consume cultivator durability for each additional plant. The first plant keeps its vanilla cost."); extraSpacing = Config.Bind<float>("13 - Grid Alignment", "ExtraSpacing", 0f, new ConfigDescription("Extra distance in metres between plants, in addition to automatic spacing. Useful for larger plants from other mods.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); showCost = Config.Bind<bool>("17 - Grid Appearance", "ShowCost", true, "Show total resource costs to the right of each vanilla cost, for example 2 (18) for nine plants costing two seeds each."); showHUDKeyHints = Config.Bind<bool>("17 - Grid Appearance", "ShowHUDKeyHints", true, "Show the grid size shortcut in the build HUD."); showGridDirections = Config.Bind<bool>("17 - Grid Appearance", "ShowGridDirections", true, "Show row, column and snapping direction lines."); cycleSizeKey.SettingChanged += GridConfigEvents.KeybindsChanged; showGridDirections.SettingChanged += delegate { GameObject directionRenderer = PlantationsGridPreview.DirectionRenderer; if (directionRenderer != null) { directionRenderer.SetActive(false); } }; extraSpacing.SettingChanged += delegate { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { localPlayer.SetupPlacementGhost(); } }; RemoveLegacySettings(); Config.Save(); } finally { Config.SaveOnConfigSet = saveOnConfigSet; } } internal void CycleSize() { size = ((size == 5) ? 2 : (size + 1)); PlantationsGridPreview.ResizeGrid(); } private void RemoveLegacySettings() { //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown if (!File.Exists(Config.ConfigFilePath)) { return; } HashSet<string> hashSet = new HashSet<string> { "11 - Planting Grid", "12 - Grid Controls", "13 - Grid Alignment", "14 - Grid Placement", "15 - Grid Performance", "16 - Grid Pickables", "17 - Grid Appearance" }; string text = string.Empty; string[] array = File.ReadAllLines(Config.ConfigFilePath); foreach (string text2 in array) { string text3 = text2.Trim(); if (text3.StartsWith("[") && text3.EndsWith("]")) { text = text3.Substring(1, text3.Length - 2); } else { if (!hashSet.Contains(text) || text3.StartsWith("#")) { continue; } int num = text3.IndexOf('='); if (num >= 1) { string text4 = text3.Substring(0, num).Trim(); ConfigDefinition val = new ConfigDefinition(text, text4); if (!Config.ContainsKey(val)) { Config.Bind<string>(text, text4, string.Empty, (ConfigDescription)null); Config.Remove(val); } } } } } internal float GetPickableSpacing(GridPickableDefinition pickable) { string key = pickable.key; if (1 == 0) { } float result; switch (key) { case "Pickable_Dandelion": case "Pickable_Thistle": result = 0.75f; break; case "Pickable_Mushroom": case "Pickable_Mushroom_blue": case "Pickable_Mushroom_yellow": result = 0.5f; break; case "BlueberryBush": case "RaspberryBush": case "LingonberryBush": result = 1.5f; break; case "Pickable_Fiddlehead": case "Pickable_SmokePuff": case "CloudberryBush": result = 1f; break; default: result = ((pickable.Piece.m_harvestRadius > 0f) ? pickable.Piece.m_harvestRadius : DefaultGridSpacing); break; } if (1 == 0) { } return result; } internal bool TryGetScatterRadius(out float radius) { radius = 0f; return false; } internal bool TryGetScatterAngle(out float angle) { angle = 0f; return false; } } internal static class GridConfigEvents { internal static void KeybindsChanged(object sender, EventArgs e) { Code_PlantationsGridHints.UpdateKeyHintText(); } internal static void ApplyColors() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)PlantationsGridPreview.DirectionRenderer)) { PlantationsGridPreview.LineRenderers[0].startColor = PlantationsGridContext.config.RowStartColor; PlantationsGridPreview.LineRenderers[0].endColor = PlantationsGridContext.config.RowEndColor; PlantationsGridPreview.LineRenderers[1].startColor = PlantationsGridContext.config.ColumnStartColor; PlantationsGridPreview.LineRenderers[1].endColor = PlantationsGridContext.config.ColumnEndColor; PlantationsGridPreview.LineRenderers[2].startColor = PlantationsGridContext.config.SnapStartColor; PlantationsGridPreview.LineRenderers[2].endColor = PlantationsGridContext.config.SnapEndColor; } } } internal static class PlantationsGridState { internal static Vector3 BasePosition; internal static Vector3 RowDirection; internal static Vector3 ColumnDirection; internal static Quaternion BaseRotation; internal static Quaternion FixedRotation; internal static bool AltPlacement; internal static GameObject PlacementGhost; internal static Piece Piece; internal static Plant Plant; internal static string LastSelectedPlantName = ""; internal static Vector3 SnapDirection; internal static Vector3 SavedRowDirection; internal static Vector3 SavedColumnDirection; internal static Quaternion? SavedBaseRotation; internal static void SetReferences(GameObject rootGhost) { PlacementGhost = rootGhost; Plant = rootGhost.GetComponent<Plant>(); Piece = rootGhost.GetComponent<Piece>(); LastSelectedPlantName = null; if (!Object.op_Implicit((Object)(object)Plant)) { return; } foreach (KeyValuePair<string, GridCropCatalog> item in GridCropCatalog.Registry) { if (item.Value.PlantName == ((Object)rootGhost).name) { LastSelectedPlantName = item.Key; break; } } } internal static void Update(Vector3 playerPosition) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) UpdateAltPlacementMode(); UpdateBaseTransform(); UpdateFixedRotation(); UpdateGridDirectionsAndSnapping(playerPosition); } private static void UpdateAltPlacementMode() { if (PlantationsGridContext.config.ForceAltPlacement) { AltPlacement = true; return; } if (ZInput.IsNonClassicFunctionality() && ZInput.IsGamepadActive()) { AltPlacement = Player.m_localPlayer.m_altPlace; return; } bool button = ZInput.GetButton("AltPlace"); bool flag = ZInput.GetButton("JoyAltPlace") && !ZInput.GetButton("JoyRotate"); AltPlacement = button || flag; } private static void UpdateBaseTransform() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) BasePosition = PlacementGhost.transform.position; BaseRotation = PlacementGhost.transform.rotation; } private static void UpdateFixedRotation() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) FixedRotation = BaseRotation; Vector3 eulerAngles = ((Quaternion)(ref FixedRotation)).eulerAngles; eulerAngles.y = Mathf.Round(eulerAngles.y / 90f) * 90f; ((Quaternion)(ref FixedRotation)).eulerAngles = eulerAngles; } private static void UpdateGridDirectionsAndSnapping(Vector3 playerPosition) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) float pieceSpacing = PlantationsGridRules.GetPieceSpacing(PlacementGhost); ResetGridDirections(); if (PlantationsGridContext.config.SnapActive) { if (PlantationsGridSnapping.FindSnapPoints(pieceSpacing)) { return; } ResetGridDirections(); } RowDirection = BaseRotation * RowDirection * pieceSpacing; ColumnDirection = BaseRotation * ColumnDirection * pieceSpacing; void ResetGridDirections() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) RowDirection = (PlantationsGridContext.config.GloballyAlignGridDirections ? Vector3.forward : Utils.DirectionXZ(BasePosition - playerPosition)); ColumnDirection = Vector3.Cross(Vector3.up, RowDirection); } } } internal sealed class PlantationsGridGhost : MonoBehaviour { internal Piece piece; internal Plant plant; internal int lastUpdatedVersion = -1; public void Init() { piece = ((Component)this).GetComponent<Piece>(); plant = ((Component)this).GetComponent<Plant>(); } } internal static class PlantationsGridValidation { private static readonly Dictionary<Biome, GridPlacementStatus> TemperatureBiomeStatus = new Dictionary<Biome, GridPlacementStatus> { { (Biome)32, GridPlacementStatus.TooHot }, { (Biome)64, GridPlacementStatus.TooCold }, { (Biome)4, GridPlacementStatus.TooCold } }; internal static GridPlacementStatus EvaluateStatus(GameObject ghost, GridPlacementStatus baseStatus = GridPlacementStatus.Healthy) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Invalid comparison between Unknown and I4 //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) Piece piece; Plant plant; if ((Object)(object)ghost == (Object)(object)PlantationsGridState.PlacementGhost) { piece = PlantationsGridState.Piece; plant = PlantationsGridState.Plant; } else { PlantationsGridGhost component = ghost.GetComponent<Planta