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 Planting Tools v1.0.1
DigiPlanting.dll
Decompiled an hour ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using DigiCore; using HarmonyLib; using Microsoft.CodeAnalysis; using PlantingTools; using Splatform; using TMPro; using Unity.Collections; using Unity.Jobs; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: AssemblyCompany("DigiPlanting")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("DigiPlanting")] [assembly: AssemblyTitle("DigiPlanting")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } internal static class SettingOrder { internal sealed class ConfigurationManagerAttributes { public int? Order; } internal static void Apply(ConfigFile config) { //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown FieldInfo fieldInfo = AccessTools.Field(typeof(ConfigEntryBase), "<Description>k__BackingField"); if (fieldInfo == null) { return; } int num = 1000; foreach (ConfigDefinition item in config.Keys.ToList()) { ConfigEntryBase val = config[item]; ConfigDescription description = val.Description; object[] array = ((description != null) ? description.Tags : null) ?? new object[0]; object obj = array.FirstOrDefault((object t) => t != null && t.GetType().Name == "ConfigurationManagerAttributes"); if (obj != null) { FieldInfo fieldInfo2 = AccessTools.Field(obj.GetType(), "Order"); if (fieldInfo2 != null && fieldInfo2.GetValue(obj) == null) { fieldInfo2.SetValue(obj, num); } } else { fieldInfo.SetValue(val, (object?)new ConfigDescription(((description != null) ? description.Description : null) ?? "", (description != null) ? description.AcceptableValues : null, array.Concat(new object[1] { new ConfigurationManagerAttributes { Order = num } }).ToArray())); } num--; } } } internal static class StoreRules { private static bool _resolved; private static MethodInfo _readMarker; private static PropertyInfo _settings; private static PropertyInfo _useMarkers; private static PropertyInfo _canDeposit; private static PropertyInfo _canWithdraw; private static MethodInfo _isProtected; private static void Resolve() { if (_resolved) { return; } _resolved = true; try { Type type = AccessTools.TypeByName("LocalCraftFromStoragePrime.ContainerPolicyApi"); Type type2 = AccessTools.TypeByName("LocalCraftFromStoragePrime.ContainerMarkerPolicy"); Type type3 = AccessTools.TypeByName("LocalCraftFromStoragePrime.Plugin"); if (!(type == null) && !(type2 == null) && !(type3 == null)) { _readMarker = AccessTools.Method(type, "ReadMarker", new Type[2] { typeof(Inventory), typeof(bool) }, (Type[])null); _settings = AccessTools.Property(type3, "Settings"); _useMarkers = ((_settings != null) ? AccessTools.Property(_settings.PropertyType, "UseContainerMarkers") : null); _canDeposit = AccessTools.Property(type2, "CanDeposit"); _canWithdraw = AccessTools.Property(type2, "CanWithdraw"); _isProtected = AccessTools.Method(type2, "IsProtectedPosition", new Type[2] { typeof(int), typeof(int) }, (Type[])null); } } catch (Exception) { _readMarker = null; } } private static object Marker(Inventory inv) { Resolve(); if (_readMarker == null || _canDeposit == null || _canWithdraw == null || _isProtected == null) { return null; } try { bool flag = true; if (_settings != null && _useMarkers != null) { flag = (bool)_useMarkers.GetValue(_settings.GetValue(null)); } return _readMarker.Invoke(null, new object[2] { inv, flag }); } catch (Exception) { return null; } } internal static bool CanDeposit(Inventory inv) { object obj = Marker(inv); if (obj != null) { return (bool)_canDeposit.GetValue(obj); } return true; } internal static bool CanWithdraw(Inventory inv) { object obj = Marker(inv); if (obj != null) { return (bool)_canWithdraw.GetValue(obj); } return true; } internal static bool IsProtected(Inventory inv, ItemData item) { return IsProtectedSlot(inv, item.m_gridPos.x, item.m_gridPos.y); } internal static bool IsProtectedSlot(Inventory inv, int x, int y) { object obj = Marker(inv); if (obj != null) { return (bool)_isProtected.Invoke(obj, new object[2] { x, y }); } return false; } internal static Func<int, int, bool> ProtectedSlots(Inventory inv) { object m = Marker(inv); if (m == null) { return null; } return (int x, int y) => (bool)_isProtected.Invoke(m, new object[2] { x, y }); } internal static Container PickOutputChest(List<Container> nearestFirst, GameObject prefab, int amount) { string shared = prefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_name; List<Container> source = nearestFirst.Where((Container c) => CanDeposit(c.GetInventory()) && c.GetInventory().CanAddItem(prefab, amount)).ToList(); return ((IEnumerable<Container>)source).FirstOrDefault((Func<Container, bool>)((Container c) => c.GetInventory().GetAllItems().Any((ItemData i) => i?.m_shared != null && i.m_shared.m_name == shared && !IsProtected(c.GetInventory(), i)))) ?? source.FirstOrDefault(); } internal static bool TakeOne(List<Container> nearestFirst, Func<ItemData, bool> match, out ItemData taken) { foreach (Container item in nearestFirst) { Inventory inv = item.GetInventory(); if (CanWithdraw(inv)) { ItemData val = ((IEnumerable<ItemData>)inv.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => match(i) && !IsProtected(inv, i))); if (val != null) { taken = val.Clone(); inv.RemoveOneItem(val); return true; } } } taken = null; return false; } } namespace DigiCore { public static class ChestFlags { public const string NoStore = "digi_nostore"; public static bool StoreBlocked(Container chest) { if ((Object)(object)chest == (Object)null) { return false; } ZNetView component = ((Component)chest).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { return component.GetZDO().GetBool("digi_nostore", false); } return false; } } public sealed class ModuleInfo { public readonly Type Type; public readonly string Title; public readonly string OldGuid; public readonly string Description; public readonly string[] Requires; public readonly bool DefaultOn; public readonly bool OffOnce; public readonly string FormerTitle; public ModuleInfo(Type type, string title, string oldGuid, string description, string[] requires = null, bool defaultOn = true, bool offOnce = false, string formerTitle = null) { OffOnce = offOnce; FormerTitle = formerTitle; Type = type; Title = title; OldGuid = oldGuid; Description = description; Requires = requires ?? new string[0]; DefaultOn = defaultOn; } } public abstract class DigiPlugin : BaseUnityPlugin { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Func<string, string> <>9__15_0; public static Func<string, bool> <>9__15_1; public static Func<string, bool> <>9__15_2; public static Func<string, string> <>9__15_3; public static Func<string, bool> <>9__15_4; public static Func<string, string> <>9__15_5; public static Func<string, string[]> <>9__24_0; public static Func<string[], string> <>9__24_1; public static Func<string[], string> <>9__24_4; public static Func<IGrouping<string, string[]>, string> <>9__24_2; public static PopupButtonCallback <>9__24_3; public static Func<string, bool> <>9__29_0; internal string <Awake>b__15_0(string l) { return l.Trim(); } internal bool <Awake>b__15_1(string l) { return l.Length > 0; } internal bool <Awake>b__15_2(string r) { return !Chainloader.PluginInfos.ContainsKey(r); } internal string <Awake>b__15_3(string r) { if (!RequirementNames.TryGetValue(r, out var value)) { return r; } return value; } internal bool <Awake>b__15_4(string r) { return !Chainloader.PluginInfos.ContainsKey(r); } internal string <Awake>b__15_5(string r) { if (!RequirementNames.TryGetValue(r, out var value)) { return r; } return value; } internal string[] <ShowDuplicates>b__24_0(string d) { return d.Split(new char[1] { '|' }); } internal string <ShowDuplicates>b__24_1(string[] d) { return d[0]; } internal string <ShowDuplicates>b__24_2(IGrouping<string, string[]> g) { return "<b>" + g.Key + ":</b> " + string.Join(", ", g.Select((string[] d) => d[1])); } internal string <ShowDuplicates>b__24_4(string[] d) { return d[1]; } internal void <ShowDuplicates>b__24_3() { UnifiedPopup.Pop(); } internal bool <Apply>b__29_0(string r) { return !Chainloader.PluginInfos.ContainsKey(r); } } public const string ModulesSection = "0 - Sub-mods"; internal static DigiPlugin StartingHost; internal static ModuleInfo StartingModule; private static readonly Dictionary<string, string> RequirementNames = new Dictionary<string, string> { { "randyknapp.mods.epicloot", "Epic Loot" }, { "com.jotunn.jotunn", "Jotunn" }, { "ValheimLegends", "Valheim Legends" }, { "vapok.mods.adventurebackpacks", "Adventure Backpacks" }, { "MidnightsFX.StarLevelSystem", "Star Level System" }, { "sosal.nordicrugs", "Nordic Rugs" }, { "LuminairPrime.valheim.localcraftfromstorageprime", "Local Craft From Storage Prime" } }; private readonly Dictionary<ModuleInfo, DigiModule> _running = new Dictionary<ModuleInfo, DigiModule>(); private readonly Dictionary<ModuleInfo, ConfigEntry<bool>> _switches = new Dictionary<ModuleInfo, ConfigEntry<bool>>(); private HashSet<string> _migrated; private const string DuplicatesKey = "digi.valheim.duplicates"; private const string DuplicatesShownKey = "digi.valheim.duplicates.shown"; protected abstract ModuleInfo[] Modules { get; } protected virtual bool Standalone => false; internal bool IsStandalone => Standalone; private string MigratedFile => Path.Combine(Paths.ConfigPath, ((BaseUnityPlugin)this).Info.Metadata.GUID + ".migrated.txt"); private static List<string> Duplicates { get { List<string> list = AppDomain.CurrentDomain.GetData("digi.valheim.duplicates") as List<string>; if (list == null) { list = new List<string>(); AppDomain.CurrentDomain.SetData("digi.valheim.duplicates", list); } return list; } } protected virtual void Awake() { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; ((BaseUnityPlugin)this).Config.Save(); _migrated = (File.Exists(MigratedFile) ? new HashSet<string>(from l in File.ReadAllLines(MigratedFile) select l.Trim() into l where l.Length > 0 select l) : new HashSet<string>()); bool flag = !_migrated.Contains("#switches"); ModuleInfo[] modules; if (Standalone) { modules = Modules; foreach (ModuleInfo moduleInfo in modules) { List<string> list = moduleInfo.Requires.Where((string r) => !Chainloader.PluginInfos.ContainsKey(r)).ToList(); if (list.Count > 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(moduleInfo.Title + ": not started, needs " + string.Join(" and ", list.Select((string r) => (!RequirementNames.TryGetValue(r, out var value2)) ? r : value2)) + ".")); } else { StartModule(moduleInfo); } } return; } modules = Modules; foreach (ModuleInfo moduleInfo2 in modules) { List<string> list2 = moduleInfo2.Requires.Where((string r) => !Chainloader.PluginInfos.ContainsKey(r)).ToList(); string value2; string text = ((moduleInfo2.Requires.Length == 0) ? "" : (" Needs " + string.Join(" and ", moduleInfo2.Requires.Select((string r) => (!RequirementNames.TryGetValue(r, out value2)) ? r : value2)) + ".")); ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Sub-mods", moduleInfo2.Title, moduleInfo2.DefaultOn, moduleInfo2.Description + text); if (flag && !moduleInfo2.DefaultOn && File.Exists(OldConfigPath(moduleInfo2))) { val.Value = true; } if (moduleInfo2.FormerTitle != null && !_migrated.Contains("#renamed:" + moduleInfo2.FormerTitle)) { if (File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath) && ReadCfg(((BaseUnityPlugin)this).Config.ConfigFilePath).TryGetValue("0 - Sub-mods\n" + moduleInfo2.FormerTitle, out var value) && bool.TryParse(value, out var result)) { val.Value = result; } Remember("#renamed:" + moduleInfo2.FormerTitle); } if (moduleInfo2.OffOnce && !_migrated.Contains("#off:" + moduleInfo2.OldGuid)) { val.Value = false; Remember("#off:" + moduleInfo2.OldGuid); } _switches[moduleInfo2] = val; ModuleInfo captured = moduleInfo2; val.SettingChanged += delegate { Apply(captured); }; if (list2.Count > 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(moduleInfo2.Title + ": off, needs " + string.Join(", ", list2) + ".")); } } if (flag) { Remember("#switches"); } modules = Modules; foreach (ModuleInfo module in modules) { Apply(module); } } private void Start() { foreach (KeyValuePair<ModuleInfo, DigiModule> item in _running.ToList()) { if (!((Object)(object)item.Value == (Object)null) && !(item.Key.OldGuid == ((BaseUnityPlugin)this).Info.Metadata.GUID) && Chainloader.PluginInfos.ContainsKey(item.Key.OldGuid)) { item.Value.Teardown(); _running.Remove(item.Key); Forget(item.Key.OldGuid); ReportDuplicate(item.Key); } } SettingOrder.Apply(((BaseUnityPlugin)this).Config); if (!Application.isBatchMode) { ((MonoBehaviour)this).StartCoroutine(ShowDuplicates()); } } private void ReportDuplicate(ModuleInfo module) { if (IsOurSingle(module.OldGuid)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(module.Title + ": runs as its own mod (" + module.OldGuid + "), so the copy in " + ((BaseUnityPlugin)this).Info.Metadata.Name + " stays off.")); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)(module.Title + ": not started, because the separate mod (" + module.OldGuid + ") is installed too. Remove that one.")); string item = ((BaseUnityPlugin)this).Info.Metadata.Name.Replace("Digi's ", "") + "|" + module.Title; if (!Duplicates.Contains(item)) { Duplicates.Add(item); } } } private static bool IsOurSingle(string guid) { if (!Chainloader.PluginInfos.TryGetValue(guid, out var value) || (Object)(object)value.Instance == (Object)null) { return false; } Type type = ((object)value.Instance).GetType(); while (type != null) { if (type.FullName == "DigiCore.DigiPlugin") { return true; } type = type.BaseType; } return false; } internal void ReportReplaced(string what) { string item = ((BaseUnityPlugin)this).Info.Metadata.Name.Replace("Digi's ", "") + "|" + what; if (!Duplicates.Contains(item)) { Duplicates.Add(item); } } private IEnumerator ShowDuplicates() { while ((Object)(object)FejdStartup.instance == (Object)null || !UnifiedPopup.IsAvailable()) { yield return (object)new WaitForSeconds(0.5f); } yield return (object)new WaitForSeconds(1f); if (Duplicates.Count == 0 || AppDomain.CurrentDomain.GetData("digi.valheim.duplicates.shown") != null) { yield break; } AppDomain.CurrentDomain.SetData("digi.valheim.duplicates.shown", true); IEnumerable<string> values = from d in Duplicates select d.Split(new char[1] { '|' }) into d group d by d[0] into g select "<b>" + g.Key + ":</b> " + string.Join(", ", g.Select((string[] d) => d[1])); string text = "These mods are installed twice: on their own and inside one of our combined mods.\n\n" + string.Join("\n", values) + "\n\nThe copy in the combined mod stays off until you remove the separate ones in your mod manager (or make a new profile with Digi Modpack). Your settings are copied over."; object obj = <>c.<>9__24_3; if (obj == null) { PopupButtonCallback val = delegate { UnifiedPopup.Pop(); }; <>c.<>9__24_3 = val; obj = (object)val; } UnifiedPopup.Push((PopupBase)new WarningPopup("Mods installed twice", text, (PopupButtonCallback)obj, false)); } private static string OldConfigPath(ModuleInfo module) { return Path.Combine(Paths.ConfigPath, module.OldGuid + ".cfg"); } internal bool FirstTime(string key) { if (_migrated == null || _migrated.Contains(key)) { return false; } Remember(key); return true; } private void Remember(string key) { if (!_migrated.Add(key)) { return; } try { File.AppendAllText(MigratedFile, key + Environment.NewLine); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not write " + MigratedFile + ": " + ex.Message)); } } private void Forget(string key) { if (!_migrated.Remove(key)) { return; } try { File.WriteAllLines(MigratedFile, _migrated.ToArray()); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not write " + MigratedFile + ": " + ex.Message)); } } private void Apply(ModuleInfo module) { bool value = _switches[module].Value; _running.TryGetValue(module, out var value2); if (value && (Object)(object)value2 == (Object)null) { if (!module.Requires.Any((string r) => !Chainloader.PluginInfos.ContainsKey(r))) { if (module.OldGuid != ((BaseUnityPlugin)this).Info.Metadata.GUID && Chainloader.PluginInfos.ContainsKey(module.OldGuid)) { ReportDuplicate(module); } else { StartModule(module); } } } else if (!value && (Object)(object)value2 != (Object)null) { value2.Teardown(); _running.Remove(module); ((BaseUnityPlugin)this).Logger.LogInfo((object)(module.Title + ": switched off.")); } } private void StartModule(ModuleInfo module) { StartingHost = this; StartingModule = module; try { DigiModule digiModule = (DigiModule)(object)((Component)this).gameObject.AddComponent(module.Type); digiModule.Host = this; digiModule.Info2 = module; _running[module] = digiModule; MigrateOldSettings(module, digiModule); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"{module.Title} could not start: {arg}"); } finally { StartingHost = null; StartingModule = null; } SettingOrder.Apply(((BaseUnityPlugin)this).Config); } private void MigrateOldSettings(ModuleInfo module, DigiModule component) { if (_migrated.Contains(module.OldGuid) || module.OldGuid == ((BaseUnityPlugin)this).Info.Metadata.GUID) { return; } string path = OldConfigPath(module); if (File.Exists(path) && component.ConfigOrNull != null) { Dictionary<string, string> dictionary = ReadCfg(path); int num = 0; foreach (ModuleConfig.Bound entry in component.ConfigOrNull.Entries) { if (dictionary.TryGetValue(entry.Section + "\n" + entry.Key, out var value)) { try { entry.Entry.SetSerializedValue(value); num++; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(module.Title + ": could not copy '" + entry.Key + "': " + ex.Message)); } } } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"{module.Title}: copied {num} setting(s) from {Path.GetFileName(path)}."); } Remember(module.OldGuid); } private static Dictionary<string, string> ReadCfg(string path) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); string text = ""; string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0 || text2.StartsWith("#")) { continue; } if (text2.StartsWith("[") && text2.EndsWith("]")) { text = text2.Substring(1, text2.Length - 2); continue; } int num = text2.IndexOf(" = ", StringComparison.Ordinal); if (num > 0) { dictionary[text + "\n" + text2.Substring(0, num).Trim()] = text2.Substring(num + 3); } } return dictionary; } protected virtual void OnDestroy() { foreach (DigiModule item in _running.Values.ToList()) { item?.Teardown(); } _running.Clear(); } public bool IsRunning(Type moduleType) { return _running.Any((KeyValuePair<ModuleInfo, DigiModule> p) => p.Key.Type == moduleType && (Object)(object)p.Value != (Object)null); } } public abstract class DigiModule : MonoBehaviour { internal DigiPlugin Host; internal ModuleInfo Info2; private ModuleConfig _config; private ManualLogSource _logger; private Harmony _harmony; internal ModuleConfig ConfigOrNull => _config; protected ModuleConfig Config => _config ?? (_config = new ModuleConfig(((BaseUnityPlugin)(Host ?? DigiPlugin.StartingHost)).Config, (Host ?? DigiPlugin.StartingHost).IsStandalone ? null : (Info2 ?? DigiPlugin.StartingModule).Title)); protected ManualLogSource Logger => _logger ?? (_logger = Logger.CreateLogSource("Digi's " + (Info2 ?? DigiPlugin.StartingModule)?.Title)); protected Harmony ModuleHarmony { get { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_004a: Expected O, but got Unknown Harmony obj = _harmony; if (obj == null) { Harmony val = new Harmony(((object)this).GetType().Namespace?.ToLowerInvariant() + "." + Guid.NewGuid().ToString("N")); Harmony val2 = val; _harmony = val; obj = val2; } return obj; } } protected void ReportReplacedMod(string what) { (Host ?? DigiPlugin.StartingHost)?.ReportReplaced(what); } protected bool FirstTime(string key) { return (Host ?? DigiPlugin.StartingHost)?.FirstTime("#once:" + (Info2 ?? DigiPlugin.StartingModule)?.Title + ":" + key) ?? false; } protected Harmony PatchModule(Type type) { ModuleHarmony.PatchAll(type); return ModuleHarmony; } protected Harmony PatchModuleNamespace() { string text = ((object)this).GetType().Namespace; Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(((object)this).GetType().Assembly); foreach (Type type in typesFromAssembly) { if (type.Namespace == text || (type.Namespace != null && text != null && type.Namespace.StartsWith(text + "."))) { ModuleHarmony.CreateClassProcessor(type).Patch(); } } return ModuleHarmony; } internal void Teardown() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex) { Logger.LogWarning((object)("Unpatch: " + ex.Message)); } Object.Destroy((Object)(object)this); } } public sealed class ModuleConfig { public sealed class Bound { public string Section; public string Key; public ConfigEntryBase Entry; } private readonly ConfigFile _file; private readonly string _prefix; internal readonly List<Bound> Entries = new List<Bound>(); private static readonly char[] Invalid = new char[8] { '=', '\n', '\t', '\\', '"', '\'', '[', ']' }; public ConfigFile File => _file; public string ConfigFilePath => _file.ConfigFilePath; internal ModuleConfig(ConfigFile file, string title) { _file = file; _prefix = ((title == null) ? "" : (title + " - ")); } public void Reload() { } public void Save() { _file.Save(); } public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, ConfigDescription configDescription = null) { section = Clean(section); key = Clean(key); ConfigEntry<T> val = _file.Bind<T>(_prefix + section, key, defaultValue, configDescription); if (!Entries.Any((Bound b) => b.Section == section && b.Key == key)) { Entries.Add(new Bound { Section = section, Key = key, Entry = (ConfigEntryBase)(object)val }); } return val; } private static string Clean(string name) { if (name.IndexOfAny(Invalid) < 0) { return name; } string[] value = name.Split(Invalid, StringSplitOptions.None); return string.Join("", value).Trim(); } public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, string description) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown return Bind(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>())); } public ConfigEntry<T> Bind<T>(ConfigDefinition definition, T defaultValue, ConfigDescription configDescription = null) { return Bind(definition.Section, definition.Key, defaultValue, configDescription); } public bool TryGetEntry<T>(ConfigDefinition definition, out ConfigEntry<T> entry) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown return _file.TryGetEntry<T>(new ConfigDefinition(_prefix + definition.Section, definition.Key), ref entry); } } } namespace DigiPlanting { [BepInPlugin("digi.valheim.plantingtools", "Digi's Planting Tools", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : DigiPlugin { public const string Guid = "digi.valheim.plantingtools"; public const string Name = "Digi's Planting Tools"; public const string Version = "1.0.1"; protected override ModuleInfo[] Modules { get; } = new ModuleInfo[1] { new ModuleInfo(typeof(PlantingTools.Plugin), "Planting Tools", "digi.valheim.plantingtools", "Plant a whole grid of crops, saplings or bushes with one click of the cultivator, in about a second and without lag; lines up with your fields, fills a cultivated patch, Shift+E harvests everything around you.") }; } } namespace PlantingTools { internal enum Spot : byte { Ok, NoSeeds, Taken, NotCultivated, WrongBiome, NoSpace, NoSun, TooHot, TooCold, Blocked, Invalid } internal sealed class Kind { public GameObject Prefab; public Piece Piece; public Plant Plant; public string Name; public bool NeedCultivated; public bool TolerateHeat; public bool TolerateCold; public bool Tree; public Biome Biome; public float GrowRadius; public float BodyRadius; public float Spacing; public static Kind Of(GameObject prefab) { //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prefab == (Object)null) { return null; } Piece component = prefab.GetComponent<Piece>(); Plant component2 = prefab.GetComponent<Plant>(); if ((Object)(object)component == (Object)null || component.m_repairPiece || component.m_removePiece) { return null; } if ((Object)(object)component2 == (Object)null && (Object)(object)prefab.GetComponent<Pickable>() == (Object)null) { return null; } if ((Object)(object)component2 != (Object)null && component2.m_attachDistance > 0f) { return null; } Kind kind = new Kind { Prefab = prefab, Piece = component, Plant = component2, Name = ((Object)prefab).name }; if ((Object)(object)component2 != (Object)null) { kind.NeedCultivated = component2.m_needCultivatedGround; kind.Biome = component2.m_biome; kind.TolerateHeat = component2.m_tolerateHeat; kind.TolerateCold = component2.m_tolerateCold; kind.GrowRadius = component2.m_growRadius; GameObject[] grownPrefabs = component2.m_grownPrefabs; foreach (GameObject val in grownPrefabs) { if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponent<TreeBase>() != (Object)null) { kind.Tree = true; } } if ((Object)(object)prefab.GetComponent<TreeBase>() != (Object)null) { kind.Tree = true; } Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true); foreach (Collider val2 in componentsInChildren) { if (((1 << ((Component)val2).gameObject.layer) & Grid.SpaceMask) != 0) { kind.BodyRadius = Mathf.Max(kind.BodyRadius, Radius(val2)); } } } else { kind.NeedCultivated = component.m_cultivatedGroundOnly; kind.Biome = component.m_onlyInBiome; } kind.Spacing = Plugin.SpacingFor(kind); return kind; } private static float Radius(Collider c) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_0080: Unknown result type (might be due to invalid IL or missing references) Vector3 lossyScale = ((Component)c).transform.lossyScale; float num = Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.z)); CapsuleCollider val = (CapsuleCollider)(object)((c is CapsuleCollider) ? c : null); if (val == null) { SphereCollider val2 = (SphereCollider)(object)((c is SphereCollider) ? c : null); if (val2 == null) { BoxCollider val3 = (BoxCollider)(object)((c is BoxCollider) ? c : null); if (val3 != null) { return Mathf.Max(val3.size.x * Mathf.Abs(lossyScale.x), val3.size.z * Mathf.Abs(lossyScale.z)) * 0.5f; } return 0f; } return val2.radius * num; } return val.radius * num; } public float CapsuleRadius() { float num = 0f; List<GameObject> list = new List<GameObject> { Prefab }; if ((Object)(object)Plant != (Object)null) { list.AddRange(Plant.m_grownPrefabs); } foreach (GameObject item in list) { if ((Object)(object)item != (Object)null) { CapsuleCollider[] componentsInChildren = item.GetComponentsInChildren<CapsuleCollider>(true); foreach (CapsuleCollider val in componentsInChildren) { num = Mathf.Max(num, val.radius); } } } return num; } } internal static class Grid { public static readonly int SpaceMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" }); private static readonly int RoofMask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" }); private static readonly int PickableMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "item" }); private const int MaxHits = 8; public static Kind Kind; public static bool Active; public static Vector3 Root; public static Vector3 RowStep; public static Vector3 ColumnStep; public static Quaternion Rotation; public static int Rows; public static int Columns; public static int Count; public static Vector3[] Positions = (Vector3[])(object)new Vector3[0]; public static Spot[] Spots = new Spot[0]; public static readonly int[] Tally = new int[Enum.GetValues(typeof(Spot)).Length]; public static int Version; public static int Seeds = int.MaxValue; public static float LastCheckMs; public static bool Fill; public static bool Snapped; public static string Note = ""; private static readonly int AnchorMask = SpaceMask | LayerMask.GetMask(new string[1] { "item" }); private static Vector3 _lastRoot; private static Vector3 _lastRow; private static Quaternion _lastRotation; private static int _lastRows; private static int _lastColumns; private static int _lastMax; private static int _lastQueued; private static bool _lastFill; private static float _lastSpacing; private static float _nextCheck; private static Kind _lastKind; private static Kind _familyFor; private static Heightmap _heightmap; private static bool _batchFailed; private static readonly List<int> Todo = new List<int>(); private static readonly List<PrivateArea> Wards = new List<PrivateArea>(); private static readonly List<Location> NoBuild = new List<Location>(); private static readonly Collider[] Hits = (Collider[])(object)new Collider[8]; private static readonly Collider[] Around = (Collider[])(object)new Collider[64]; private static readonly HashSet<string> Family = new HashSet<string>(); private static readonly Queue<long> Open = new Queue<long>(); private static readonly HashSet<long> Seen = new HashSet<long>(); private static bool? _rulesChanged; private static bool _probeFailed; public static void Clear() { Active = false; Kind = null; _lastKind = null; _familyFor = null; } public static void Update(Player player, GameObject ghost) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0159: 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_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) Active = false; if (Kind == null || (Object)(object)ghost == (Object)null || !ghost.activeInHierarchy || !Plugin.GridOn) { return; } Fill = Plugin.FillOn; Rows = Plugin.Rows; Columns = Plugin.Columns; if (Fill || Mathf.Min(Rows * Columns, Plugin.MaxPlants) >= 2) { Active = true; float spacing = Kind.Spacing; Vector3 position = ghost.transform.position; Rotation = ghost.transform.rotation; Vector3 val = (Plugin.WorldAligned ? Vector3.forward : Utils.DirectionXZ(position - ((Component)player).transform.position)); if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { val = Vector3.forward; } Vector3 row = Flat(Rotation * val); Vector3 column = Vector3.Cross(Vector3.up, row); Vector3 root = position; Snapped = Plugin.SnapOn && Snap(position, spacing, ref row, ref column, out root); if (!Snapped && Fill) { root = row * (Mathf.Round(Vector3.Dot(position, row) / spacing) * spacing) + column * (Mathf.Round(Vector3.Dot(position, column) / spacing) * spacing); } root.y = position.y; Root = root; RowStep = row * spacing; ColumnStep = column * spacing; if (Kind != _lastKind || Fill != _lastFill || Rows != _lastRows || Columns != _lastColumns || Plugin.MaxPlants != _lastMax || !Mathf.Approximately(spacing, _lastSpacing) || Flat2(Root - _lastRoot) > 0.0001f || Vector3.Angle(row, _lastRow) > 0.5f || Quaternion.Angle(Rotation, _lastRotation) > 0.5f || Planter.Queued != _lastQueued || Time.time >= _nextCheck) { _lastKind = Kind; _lastFill = Fill; _lastRows = Rows; _lastColumns = Columns; _lastMax = Plugin.MaxPlants; _lastSpacing = spacing; _lastRoot = Root; _lastRow = row; _lastRotation = Rotation; _lastQueued = Planter.Queued; _nextCheck = Time.time + 0.5f; Stopwatch stopwatch = Stopwatch.StartNew(); Layout(); Check(player); LastCheckMs = (float)stopwatch.Elapsed.TotalMilliseconds; } if (Count > 0 && (Snapped || Fill)) { ghost.transform.position = Positions[0]; } } } private static void Layout() { //IL_0090: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: 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_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) Note = ""; if (!Fill) { Count = Mathf.Min(Rows * Columns, Plugin.MaxPlants); Ensure(Count); for (int i = 0; i < Count; i++) { Positions[i] = Root + RowStep * (float)(i / Columns) + ColumnStep * (float)(i % Columns); } return; } Count = 0; Ensure(1); if (!Cultivated(Root)) { Positions[0] = Root; Count = 1; Note = "not on cultivated ground"; return; } int maxPlants = Plugin.MaxPlants; float num = Plugin.FillReach * Plugin.FillReach; Seen.Clear(); Open.Clear(); Seen.Add(Key(0, 0)); Open.Enqueue(Key(0, 0)); while (Open.Count > 0 && Count < maxPlants) { long num2 = Open.Dequeue(); int num3 = (int)(num2 >> 32); int num4 = (int)(num2 & 0xFFFFFFFFu); Ensure(Count + 1); Positions[Count++] = Root + RowStep * (float)num3 + ColumnStep * (float)num4; for (int j = 0; j < 4; j++) { int num5 = num3 + j switch { 1 => -1, 0 => 1, _ => 0, }; int num6 = num4 + j switch { 3 => -1, 2 => 1, _ => 0, }; long item = Key(num5, num6); if (Seen.Add(item)) { Vector3 val = Root + RowStep * (float)num5 + ColumnStep * (float)num6; if (Flat2(val - Root) <= num && Cultivated(val)) { Open.Enqueue(item); } } } } if (Open.Count > 0 && Count >= maxPlants) { Note = "more than the most plants per click"; } } private static bool Snap(Vector3 raw, float s, ref Vector3 row, ref Vector3 column, out Vector3 root) { //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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: 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_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0177: 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_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) root = raw; if (_familyFor != Kind) { _familyFor = Kind; Family.Clear(); Family.Add(Kind.Name); if ((Object)(object)Kind.Plant != (Object)null) { GameObject[] grownPrefabs = Kind.Plant.m_grownPrefabs; foreach (GameObject val in grownPrefabs) { if ((Object)(object)val != (Object)null) { Family.Add(((Object)val).name); } } } } if (!Nearest(raw, Mathf.Max(0.5f, s * 1.6f), raw, notAtFrom: false, out var found)) { return false; } if (Nearest(found, s * 1.6f, found, notAtFrom: true, out var found2)) { Vector3 val2 = Flat(found2 - found); if (Mathf.Abs(Vector3.Dot(val2, row)) >= Mathf.Abs(Vector3.Dot(val2, column))) { row = ((Vector3.Dot(val2, row) >= 0f) ? val2 : (-val2)); Vector3 val3 = Vector3.Cross(Vector3.up, row); column = ((Vector3.Dot(val3, column) >= 0f) ? val3 : (-val3)); } else { column = ((Vector3.Dot(val2, column) >= 0f) ? val2 : (-val2)); Vector3 val4 = Vector3.Cross(column, Vector3.up); row = ((Vector3.Dot(val4, row) >= 0f) ? val4 : (-val4)); } } Vector3 val5 = raw - found; int num = Mathf.RoundToInt(Vector3.Dot(val5, row) / s); int num2 = Mathf.RoundToInt(Vector3.Dot(val5, column) / s); if (num == 0 && num2 == 0) { if (Mathf.Abs(Vector3.Dot(val5, row)) >= Mathf.Abs(Vector3.Dot(val5, column))) { num = ((Vector3.Dot(val5, row) >= 0f) ? 1 : (-1)); } else { num2 = ((Vector3.Dot(val5, column) >= 0f) ? 1 : (-1)); } } root = found + row * (s * (float)num) + column * (s * (float)num2); if (Mathf.Abs(num) >= Mathf.Abs(num2)) { if (num < 0) { row = -row; } } else if (num2 < 0) { column = -column; } return true; } private static bool Nearest(Vector3 center, float radius, Vector3 from, bool notAtFrom, out Vector3 found) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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) found = Vector3.zero; float num = float.MaxValue; float num2 = radius * radius; int num3 = Physics.OverlapSphereNonAlloc(center, radius, Around, AnchorMask); for (int i = 0; i < num3; i++) { ZNetView componentInParent = ((Component)Around[i]).GetComponentInParent<ZNetView>(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsValid() && Family.Contains(Utils.GetPrefabName(((Component)componentInParent).gameObject))) { Vector3 position = ((Component)componentInParent).transform.position; float num4 = Flat2(position - from); if ((!notAtFrom || !(num4 < 0.0025f)) && !(Flat2(position - center) > num2) && !(num4 >= num)) { num = num4; found = position; } } } if (Planter.Left > 0 && Planter.Nearest(center, radius, Kind.Prefab, from, notAtFrom, out var found2, out var bestD) && bestD < num) { num = bestD; found = found2; } return num < float.MaxValue; } private static Vector3 Flat(Vector3 v) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) v.y = 0f; if (!(((Vector3)(ref v)).sqrMagnitude > 1E-08f)) { return Vector3.forward; } return ((Vector3)(ref v)).normalized; } private static float Flat2(Vector3 v) { //IL_0000: 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_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) return v.x * v.x + v.z * v.z; } private static long Key(int i, int j) { return ((long)i << 32) | (uint)j; } private static bool Cultivated(Vector3 p) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) Heightmap val = HeightmapAt(p); if ((Object)(object)val != (Object)null) { return val.IsCultivated(p); } return false; } private static void Ensure(int n) { if (Positions.Length < n) { int newSize = Mathf.Max(new int[3] { n, Positions.Length * 2, 64 }); Array.Resize(ref Positions, newSize); Array.Resize(ref Spots, newSize); } } private static void Check(Player player) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Invalid comparison between Unknown and I4 //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Invalid comparison between Unknown and I4 //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Invalid comparison between Unknown and I4 //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) bool flag = (Object)(object)Kind.Plant != (Object)null; float num = float.MaxValue; float num2 = float.MinValue; float num3 = float.MaxValue; float num4 = float.MinValue; for (int i = 0; i < Count; i++) { Vector3 val = Positions[i]; if (val.x < num) { num = val.x; } if (val.x > num2) { num2 = val.x; } if (val.z < num3) { num3 = val.z; } if (val.z > num4) { num4 = val.z; } } Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor((num + num2) * 0.5f, Root.y, (num3 + num4) * 0.5f); Vector2 val3 = new Vector2(num2 - num, num4 - num3); float num5 = ((Vector2)(ref val3)).magnitude * 0.5f + Kind.Spacing; Wards.Clear(); foreach (PrivateArea allArea in PrivateArea.m_allAreas) { if ((Object)(object)allArea != (Object)null && allArea.IsEnabled() && !allArea.HaveLocalAccess() && allArea.IsInside(val2, num5)) { Wards.Add(allArea); } } NoBuild.Clear(); foreach (Location s_allLocation in Location.s_allLocations) { if ((Object)(object)s_allLocation != (Object)null && s_allLocation.m_noBuild && s_allLocation.IsInside(val2, num5, true)) { NoBuild.Add(s_allLocation); } } bool flag2 = ShieldGenerator.m_instances.Count > 0; float distance = Kind.Spacing * 0.5f; Todo.Clear(); float y = default(float); for (int j = 0; j < Count; j++) { Vector3 val4 = Positions[j]; Spot spot = Spot.Ok; Heightmap val5 = HeightmapAt(val4); if ((Object)(object)val5 == (Object)null || !val5.GetWorldHeight(val4, ref y)) { spot = Spot.Invalid; } else { val4.y = y; if (Wards.Count > 0 && !PrivateArea.CheckAccess(val4, 0f, false, false)) { spot = Spot.Blocked; } else if (NoBuild.Count > 0 && InsideNoBuild(val4)) { spot = Spot.Blocked; } else { Biome biome = val5.GetBiome(val4, 0.02f, false); if ((int)Kind.Biome != 0 && (biome & Kind.Biome) == 0) { spot = Spot.WrongBiome; } else if (Kind.NeedCultivated && !val5.IsCultivated(val4)) { spot = Spot.NotCultivated; } else if (flag && !Kind.TolerateHeat && (int)biome == 32 && (!flag2 || !ShieldGenerator.IsInsideShield(val4))) { spot = Spot.TooHot; } else if (flag && !Kind.TolerateCold && ((int)biome == 64 || (int)biome == 4) && (!flag2 || !ShieldGenerator.IsInsideShield(val4))) { spot = Spot.TooCold; } else if (Planter.Left > 0 && Planter.Near(val4, distance)) { spot = Spot.Taken; } } } Positions[j] = val4; Spots[j] = spot; if (spot == Spot.Ok) { Todo.Add(j); } } if (!_batchFailed) { try { Batched(flag); } catch (Exception ex) { _batchFailed = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Batched physics checks are not available here, checking one by one: " + ex.Message)); } OneByOne(flag); } } else { OneByOne(flag); } if (flag && GameRulesChanged()) { AskTheGame(player); } Seeds = Plugin.ExtraPlantsPaid(player, Kind); int num6 = 0; for (int k = 1; k < Count; k++) { if (Spots[k] == Spot.Ok) { if (num6 < Seeds) { num6++; } else { Spots[k] = Spot.NoSeeds; } } } Array.Clear(Tally, 0, Tally.Length); for (int l = 0; l < Count; l++) { Tally[(uint)Spots[l]]++; } Version++; } private static void Batched(bool plant) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) int count = Todo.Count; if (count == 0) { return; } NativeArray<OverlapSphereCommand> val = default(NativeArray<OverlapSphereCommand>); val..ctor(count, (Allocator)3, (NativeArrayOptions)1); NativeArray<ColliderHit> val2 = default(NativeArray<ColliderHit>); val2..ctor(count * 8, (Allocator)3, (NativeArrayOptions)1); NativeArray<RaycastCommand> val3 = default(NativeArray<RaycastCommand>); val3..ctor(plant ? count : 0, (Allocator)3, (NativeArrayOptions)1); NativeArray<RaycastHit> val4 = default(NativeArray<RaycastHit>); val4..ctor(plant ? count : 0, (Allocator)3, (NativeArrayOptions)1); try { QueryParameters val5 = default(QueryParameters); ((QueryParameters)(ref val5))..ctor(plant ? SpaceMask : PickableMask, false, (QueryTriggerInteraction)0, false); QueryParameters val6 = default(QueryParameters); ((QueryParameters)(ref val6))..ctor(RoofMask, false, (QueryTriggerInteraction)0, false); for (int i = 0; i < count; i++) { Vector3 val7 = Positions[Todo[i]]; val[i] = (plant ? new OverlapSphereCommand(val7, Kind.GrowRadius, val5) : new OverlapSphereCommand(val7 + Vector3.up * 0.05f, 0.05f, val5)); if (plant) { val3[i] = new RaycastCommand(val7, Vector3.up, val6, 100f); } } JobHandle val8 = OverlapSphereCommand.ScheduleBatch(val, val2, 32, 8, default(JobHandle)); if (plant) { val8 = JobHandle.CombineDependencies(val8, RaycastCommand.ScheduleBatch(val3, val4, 32, 1, default(JobHandle))); } ((JobHandle)(ref val8)).Complete(); for (int j = 0; j < count; j++) { int num = Todo[j]; if (plant) { RaycastHit val9 = val4[j]; if ((Object)(object)((RaycastHit)(ref val9)).collider != (Object)null) { Spots[num] = Spot.NoSun; continue; } } for (int k = 0; k < 8; k++) { ColliderHit val10 = val2[j * 8 + k]; if (((ColliderHit)(ref val10)).instanceID == 0) { break; } if (Blocks(((ColliderHit)(ref val10)).collider, plant)) { Spots[num] = Spot.NoSpace; break; } } } } finally { val.Dispose(); val2.Dispose(); val3.Dispose(); val4.Dispose(); } } private static void OneByOne(bool plant) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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) foreach (int item in Todo) { Vector3 val = Positions[item]; if (plant && Physics.Raycast(val, Vector3.up, 100f, RoofMask)) { Spots[item] = Spot.NoSun; continue; } int num = (plant ? Physics.OverlapSphereNonAlloc(val, Kind.GrowRadius, Hits, SpaceMask) : Physics.OverlapSphereNonAlloc(val + Vector3.up * 0.05f, 0.05f, Hits, PickableMask)); for (int i = 0; i < num; i++) { if (Blocks(Hits[i], plant)) { Spots[item] = Spot.NoSpace; break; } } } } private static bool GameRulesChanged() { if (_rulesChanged.HasValue) { return _rulesChanged.Value; } _rulesChanged = Patched("HaveGrowSpace") || Patched("HaveRoof"); if (_rulesChanged.Value) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"Another mod changes the game's plant room or roof check: spots are checked through it."); } } return _rulesChanged.Value; static bool Patched(string name) { Patches patchInfo = Harmony.GetPatchInfo((MethodBase)AccessTools.Method(typeof(Plant), name, (Type[])null, (Type[])null)); if (patchInfo != null) { return patchInfo.Prefixes.Count + patchInfo.Postfixes.Count + patchInfo.Transpilers.Count + patchInfo.Finalizers.Count > 0; } return false; } } private static void AskTheGame(Player player) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (_probeFailed || (Object)(object)player.m_placementGhost == (Object)null) { return; } Plant component = player.m_placementGhost.GetComponent<Plant>(); if ((Object)(object)component == (Object)null) { return; } Transform transform = ((Component)component).transform; Vector3 position = transform.position; try { for (int i = 0; i < Count; i++) { if (Spots[i] == Spot.NoSpace || Spots[i] == Spot.NoSun) { transform.position = Positions[i]; Spots[i] = (component.HaveRoof() ? Spot.NoSun : ((!component.HaveGrowSpace()) ? Spot.NoSpace : Spot.Ok)); } } } catch (Exception ex) { _probeFailed = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Could not ask the game's own plant check: " + ex.Message)); } } finally { transform.position = position; } } private static bool Blocks(Collider c, bool plant) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 if ((Object)(object)c == (Object)null) { return false; } if (!plant) { return true; } Plant component = ((Component)c).GetComponent<Plant>(); if (!((Object)(object)component == (Object)null)) { return (int)component.m_status == 0; } return true; } private static Heightmap HeightmapAt(Vector3 p) { //IL_0025: 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) if ((Object)(object)_heightmap != (Object)null && _heightmap.IsPointInside(p, 0f)) { return _heightmap; } _heightmap = Heightmap.FindHeightmap(p); return _heightmap; } private static bool InsideNoBuild(Vector3 p) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) foreach (Location item in NoBuild) { if ((Object)(object)item != (Object)null && item.IsInside(p, 0f, true)) { return true; } } return false; } public static bool Bad(Spot spot) { if (spot != Spot.Ok && spot != Spot.NoSeeds) { return spot != Spot.Taken; } return false; } } internal static class Harvest { public enum Replant { HarvestedCrop, SelectedCrop } private static ConfigEntry<bool> _on; private static ConfigEntry<bool> _sameKind; private static ConfigEntry<bool> _hints; private static ConfigEntry<Modifier> _key; private static ConfigEntry<Modifier> _replantKey; private static ConfigEntry<float> _radius; private static ConfigEntry<Replant> _replantWhat; private static readonly Collider[] Around = (Collider[])(object)new Collider[4096]; private static readonly HashSet<Component> Found = new HashSet<Component>(); private static readonly List<Component> Picks = new List<Component>(); private static readonly Dictionary<GameObject, List<Vector3>> ToReplant = new Dictionary<GameObject, List<Vector3>>(); private static readonly Dictionary<string, GameObject> SaplingOf = new Dictionary<string, GameObject>(); private static int _depth; private static bool _replantNow; internal static void Bind(ModuleConfig config) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown _on = config.Bind("Harvest", "Harvest around", defaultValue: true, "Hold the harvest key while you pick a crop, berry bush, mushroom or beehive: everything around it is picked at once."); _key = config.Bind("Harvest", "Harvest key", Modifier.Shift, "Hold this (left or right) while picking to pick everything around you."); _radius = config.Bind("Harvest", "Harvest radius (m)", 3f, new ConfigDescription("How far around the thing you pick the rest is picked.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>())); _sameKind = config.Bind("Harvest", "Same kind only", defaultValue: false, "Only things of the kind you picked are picked around it (only barley when you pick barley). Off: everything pickable around it."); _replantKey = config.Bind("Harvest", "Replant key", Modifier.Ctrl, "Hold this (left or right) while picking a crop to plant it again on its spot (with the harvest key too: everything picked around it). Seeds come from your bag, then nearby chests."); _replantWhat = config.Bind("Harvest", "Replant with", Replant.HarvestedCrop, "HarvestedCrop: the crop you picked. SelectedCrop: the crop chosen in the cultivator (or the picked one when none is)."); _hints = config.Bind("Display", "Harvest hints", defaultValue: true, "Aiming at a crop, bush or beehive shows the harvest and replant keys."); } internal static void Copy(Dictionary<string, string> cfg, Action<Dictionary<string, string>, string, ConfigEntry<bool>> b, Action<Dictionary<string, string>, string, ConfigEntry<float>> f, Action<Dictionary<string, string>, string, ConfigEntry<Modifier>> k) { b(cfg, "Harvesting.EnableBulkHarvest", _on); f(cfg, "Harvesting.HarvestRadius", _radius); k(cfg, "Controls.KeyboardHarvestModifierKey", _key); if (cfg.TryGetValue("Harvesting.HarvestStyle", out var value)) { _sameKind.Value = value.Trim() == "LikeResources"; } if (cfg.TryGetValue("Harvesting.ReplantStyle", out var value2)) { _replantWhat.Value = ((value2.Trim() == "SelectedCrop") ? Replant.SelectedCrop : Replant.HarvestedCrop); } } internal static void Learn(PieceTable tool) { foreach (GameObject piece in tool.m_pieces) { Plant val = (((Object)(object)piece != (Object)null) ? piece.GetComponent<Plant>() : null); if ((Object)(object)val == (Object)null) { continue; } GameObject[] grownPrefabs = val.m_grownPrefabs; foreach (GameObject val2 in grownPrefabs) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.GetComponent<Pickable>() != (Object)null && !SaplingOf.ContainsKey(((Object)val2).name)) { SaplingOf[((Object)val2).name] = piece; } } } } private static void LearnOnce() { if (SaplingOf.Count <= 0) { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("Cultivator") : null); PieceTable val2 = ((!((Object)(object)val != (Object)null)) ? null : val.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces); if ((Object)(object)val2 != (Object)null) { Learn(val2); } } } [HarmonyPatch(typeof(Player), "Interact", new Type[] { typeof(GameObject), typeof(bool), typeof(bool) })] [HarmonyPrefix] private static void PickAround(Player __instance, GameObject go, bool hold, bool alt) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)go == (Object)null) { return; } if (_depth++ == 0) { _replantNow = Plugin.Held(_replantKey.Value); } if (!_on.Value || ((Character)__instance).InAttack() || ((Character)__instance).InDodge() || (hold && Time.time - __instance.m_lastHoverInteractTime < 0.2f) || (!Plugin.Held(_key.Value) && !alt)) { return; } Interactable componentInParent = go.GetComponentInParent<Interactable>(); Component val = (Component)(object)((componentInParent is Component) ? componentInParent : null); if (!(val is Pickable) && !(val is Beehive)) { return; } Transform root = val.transform.root; int num = Physics.OverlapSphereNonAlloc(root.position, _radius.Value, Around, Grid.SpaceMask | LayerMask.GetMask(new string[1] { "item" })); Found.Clear(); Picks.Clear(); for (int i = 0; i < num; i++) { Collider val2 = Around[i]; Component componentInParent2 = (Component)(object)((Component)val2).GetComponentInParent<Pickable>(); if ((Object)(object)componentInParent2 == (Object)null) { componentInParent2 = (Component)(object)((Component)val2).GetComponentInParent<Beehive>(); } if (!((Object)(object)componentInParent2 == (Object)null) && !((Object)(object)componentInParent2.transform.root == (Object)(object)root) && Found.Add(componentInParent2) && (!_sameKind.Value || !(((Object)componentInParent2.transform.root).name != ((Object)root).name))) { Beehive val3 = (Beehive)(object)((componentInParent2 is Beehive) ? componentInParent2 : null); if (val3 == null || val3.GetHoneyLevel() >= 1) { Picks.Add(componentInParent2); } } } foreach (Component pick in Picks) { if ((Object)(object)pick != (Object)null) { ((Interactable)pick).Interact((Humanoid)(object)__instance, hold, alt); } } Picks.Clear(); Found.Clear(); } [HarmonyPatch(typeof(Player), "Interact", new Type[] { typeof(GameObject), typeof(bool), typeof(bool) })] [HarmonyFinalizer] private static Exception AfterInteract(Player __instance, Exception __exception) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || _depth == 0) { return __exception; } if (--_depth > 0) { return __exception; } _replantNow = false; if (ToReplant.Count == 0) { return __exception; } try { ReplantNow(__instance); return __exception; } finally { ToReplant.Clear(); } } [HarmonyPatch(typeof(Pickable), "Interact")] [HarmonyPrefix] private static void Picked(Pickable __instance, Humanoid character) { //IL_00de: Unknown result type (might be due to invalid IL or missing references) if (!_replantNow || (Object)(object)character != (Object)(object)Player.m_localPlayer || _depth == 0 || __instance.m_picked || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || __instance.m_enabled == 0) { return; } LearnOnce(); if (!SaplingOf.TryGetValue(Utils.GetPrefabName(((Component)__instance).gameObject), out var value)) { return; } if (_replantWhat.Value == Replant.SelectedCrop) { PieceTable buildPieces = Player.m_localPlayer.m_buildPieces; GameObject val = ((buildPieces != null) ? buildPieces.GetSelectedPrefab() : null); Plant val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Plant>() : null); if ((Object)(object)val2 != (Object)null && val2.m_attachDistance <= 0f) { value = val; } } if (!ToReplant.TryGetValue(value, out var value2)) { value2 = (ToReplant[value] = new List<Vector3>()); } value2.Add(((Component)__instance).transform.position); } private static void ReplantNow(Player player) { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) Planter.Owner(player); foreach (KeyValuePair<GameObject, List<Vector3>> item in ToReplant) { Kind kind = Kind.Of(item.Key); if (kind == null) { continue; } int num = Plugin.ExtraPlantsPaid(player, kind); int num2 = ((num == int.MaxValue) ? item.Value.Count : Mathf.Min(item.Value.Count, num + 1)); if (num2 > 0 && num != int.MaxValue) { num2 = Plugin.Pay(player, kind, num2); } if (num2 <= 0) { ((Character)player).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false); continue; } Game.instance.IncrementPlayerStat((PlayerStatType)2, (float)num2, false); for (int i = 0; i < num2; i++) { Planter.Add(item.Key, item.Value[i], Quaternion.Euler(0f, 22.5f * (float)Random.Range(0, 16), 0f)); } if (num2 < item.Value.Count) { ((Character)player).Message((MessageType)2, $"Seeds to replant {num2} of {item.Value.Count}", 0, (Sprite)null, false); } } } [HarmonyPatch(typeof(Pickable), "GetHoverText")] [HarmonyPostfix] private static void Hint(Pickable __instance, ref string __result) { if (!_hints.Value || string.IsNullOrEmpty(__result)) { return; } if (_on.Value) { __result += Localization.instance.Localize("\n[<color=yellow><b>" + Name(_key.Value) + " + $KEY_Use</b></color>] Harvest around"); } LearnOnce(); if (SaplingOf.ContainsKey(Utils.GetPrefabName(((Component)__instance).gameObject))) { __result += Localization.instance.Localize("\n[<color=yellow><b>" + Name(_replantKey.Value) + " + $KEY_Use</b></color>] Harvest and replant"); if (_on.Value) { __result += Localization.instance.Localize("\n[<color=yellow><b>" + Name(_replantKey.Value) + " + " + Name(_key.Value) + " + $KEY_Use</b></color>] Harvest around and replant"); } } } [HarmonyPatch(typeof(Beehive), "GetHoverText")] [HarmonyPostfix] private static void HiveHint(ref string __result) { if (_hints.Value && _on.Value && !string.IsNullOrEmpty(__result)) { __result += Localization.instance.Localize("\n[<color=yellow><b>" + Name(_key.Value) + " + $KEY_Use</b></color>] Harvest around"); } } private static string Name(Modifier key) { return key.ToString(); } } internal static class Planter { private struct Job { public GameObject Prefab; public Vector3 Pos; public Quaternion Rot; } private static readonly Queue<Job> Jobs = new Queue<Job>(); private static readonly Dictionary<long, List<Job>> Squares = new Dictionary<long, List<Job>>(); private static long _creator; private static PlatformUserID _platformUser; private static SkillType _skill; public static int Planted; public static int Queued; public static float LastFrameMs; public static int Left => Jobs.Count; public static void Add(GameObject prefab, Vector3 pos, Quaternion rot) { //IL_0012: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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) Job item = new Job { Prefab = prefab, Pos = pos, Rot = rot }; Jobs.Enqueue(item); Queued++; long key = Key(pos); if (!Squares.TryGetValue(key, out var value)) { value = (Squares[key] = new List<Job>()); } value.Add(item); } public static void Owner(Player player) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) _creator = player.GetPlayerID(); _platformUser = ((IUser)PlatformManager.DistributionPlatform.LocalUser).PlatformUserID; _skill = (SkillType)((!((Object)(object)player.m_buildPieces != (Object)null)) ? 106 : ((int)player.m_buildPieces.m_skill)); } public static void Work(float budgetMs) { if (Jobs.Count != 0) { Stopwatch stopwatch = Stopwatch.StartNew(); while (Jobs.Count > 0 && stopwatch.Elapsed.TotalMilliseconds < (double)budgetMs) { PlantOne(); } LastFrameMs = (float)stopwatch.Elapsed.TotalMilliseconds; } } public static void Finish() { while (Jobs.Count > 0) { PlantOne(); } } public static bool Near(Vector3 p, float distance) { //IL_0004: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) float num = distance * distance; int num2 = Mathf.FloorToInt(p.x); int num3 = Mathf.FloorToInt(p.z); int num4 = Mathf.CeilToInt(distance); for (int i = num2 - num4; i <= num2 + num4; i++) { for (int j = num3 - num4; j <= num3 + num4; j++) { if (!Squares.TryGetValue(((long)i << 32) ^ (uint)j, out var value)) { continue; } foreach (Job item in value) { float num5 = item.Pos.x - p.x; float num6 = item.Pos.z - p.z; if (num5 * num5 + num6 * num6 < num) { return true; } } } } return false; } public static bool Nearest(Vector3 center, float radius, GameObject prefab, Vector3 from, bool notAtFrom, out Vector3 found, out float bestD2) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) found = Vector3.zero; bestD2 = float.MaxValue; float num = radius * radius; int num2 = Mathf.FloorToInt(center.x); int num3 = Mathf.FloorToInt(center.z); int num4 = Mathf.CeilToInt(radius); for (int i = num2 - num4; i <= num2 + num4; i++) { for (int j = num3 - num4; j <= num3 + num4; j++) { if (!Squares.TryGetValue(((long)i << 32) ^ (uint)j, out var value)) { continue; } foreach (Job item in value) { if ((Object)(object)item.Prefab != (Object)(object)prefab) { continue; } float num5 = item.Pos.x - center.x; float num6 = item.Pos.z - center.z; if (!(num5 * num5 + num6 * num6 > num)) { float num7 = item.Pos.x - from.x; float num8 = item.Pos.z - from.z; float num9 = num7 * num7 + num8 * num8; if ((!notAtFrom || !(num9 < 0.0025f)) && !(num9 >= bestD2)) { bestD2 = num9; found = item.Pos; } } } } } return bestD2 < float.MaxValue; } public static void CopyQueued(List<Matrix4x4> into, Vector3 scale) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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) into.Clear(); foreach (Job job in Jobs) { into.Add(Matrix4x4.TRS(job.Pos, job.Rot, scale)); } } private static void PlantOne() { //IL_000c: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) Job job = Jobs.Dequeue(); long key = Key(job.Pos); if (Squares.TryGetValue(key, out var value)) { for (int i = 0; i < value.Count; i++) { if (value[i].Pos == job.Pos && (Object)(object)value[i].Prefab == (Object)(object)job.Prefab) { value.RemoveAt(i); break; } } if (value.Count == 0) { Squares.Remove(key); } } if (!((Object)(object)job.Prefab == (Object)null)) { TerrainModifier.SetTriggerOnPlaced(true); GameObject obj = Object.Instantiate<GameObject>(job.Prefab, job.Pos, job.Rot); TerrainModifier.SetTriggerOnPlaced(false); Piece component = obj.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { component.SetCreator(_creator, _platformUser); } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && (int)_skill != 0) { ((Character)localPlayer).RaiseSkill(_skill, 1f); } Planted++; } } private static long Key(Vector3 p) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) return ((long)Mathf.FloorToInt(p.x) << 32) ^ (uint)Mathf.FloorToInt(p.z); } } public enum Modifier { Ctrl, Shift, Alt } public class Plugin : DigiModule { private const string PlantEasilyGuid = "advize.PlantEasily"; private const string PlantEasilyConfig = "advize.PlantEasily.cfg"; internal static ManualLogSource Log; private static bool _running; private static ConfigEntry<bool> _gridOn; private static ConfigEntry<bool> _snapOn; private static ConfigEntry<bool> _fillOn; private static ConfigEntry<bool> _worldAligned; private static ConfigEntry<bool> _tighter; private static ConfigEntry<bool> _onlyWhereItGrows; private static ConfigEntry<bool> _allOrNothing; private static ConfigEntry<bool> _stamina; private static ConfigEntry<bool> _durability; private static ConfigEntry<bool> _randomRotation; private static ConfigEntry<bool> _preview; private static ConfigEntry<bool> _count; private static ConfigEntry<int> _rows; private static ConfigEntry<int> _columns; private static ConfigEntry<int> _maxPlants; private static ConfigEntry<float> _extraCrop; private static ConfigEntry<float> _extraSapling; private static ConfigEntry<float> _pickableSpacing; private static ConfigEntry<float> _scatter; private static ConfigEntry<float> _tilt; private static ConfigEntry<float> _budget; private static ConfigEntry<float> _fillReach; private static ConfigEntry<KeyCode> _toggleKey; private static ConfigEntry<KeyCode> _snapKey; private static ConfigEntry<KeyCode> _fillKey; private static ConfigEntry<KeyCode> _moreColumns; private static ConfigEntry<KeyCode> _fewerColumns; private static ConfigEntry<KeyCode> _moreRows; private static ConfigEntry<KeyCode> _fewerRows; private static ConfigEntry<Modifier> _sizeModifier; private static ConfigEntry<Modifier> _wheelModifier; private static TextMeshProUGUI _label; private static GameObject _labelRoot; private static List<Vector3> _clicked; private static Kind _clickedKind; private static Quaternion _clickedRotation; private static int _rotationBefore; private static bool _keepRotation; private static int _turnBefore; private static readonly Dictionary<string, ConfigEntry<float>> Bushes = new Dictionary<string, ConfigEntry<float>>(); private static readonly Dictionary<string, float> BushDefaults = new Dictionary<string, float> { { "Pickable_Dandelion", 0.75f }, { "Pickable_Fiddlehead", 1f }, { "Pickable_Mushroom", 0.5f }, { "Pickable_Mushroom_blue", 0.5f }, { "Pickable_Mushroom_yellow", 0.5f }, { "Pickable_SmokePuff", 1f }, { "Pickable_Thistle", 0.75f }, { "BlueberryBush", 1.5f }, { "RaspberryBush", 1.5f }, { "CloudberryBush", 1f }, { "LingonberryBush", 1.5f } }; private static Plugin _instance; internal static bool GridOn => _gridOn.Value; internal static bool SnapOn => _snapOn.Value; internal static bool FillOn => _fillOn.Value; internal static float FillReach => _fillReach.Value; internal static int Rows => _rows.Value; internal static int Columns => _columns.Value; internal static int MaxPlants => _maxPlants.Value; internal static bool WorldAligned => _worldAligned.Value; internal static bool ShowPreview => _preview.Value; private void Awake() { //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Expected O, but got Unknown //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected O, but got Unknown //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Expected O, but got Unknown //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Expected O, but got Unknown //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Expected O, but got Unknown //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Expected O, but got Unknown //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Expected O, but got Unknown //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Expected O, but got Unknown _instance = this; Log = base.Logger; _gridOn = base.Config.Bind("General", "Grid on", defaultValue: true, "Plant a whole grid with each click of the cultivator. The toggle key switches it while you play."); _toggleKey = base.Config.Bind<KeyCode>("General", "Toggle key", (KeyCode)289, "Turns the grid on or off."); _snapOn = base.Config.Bind("General", "Line up with fields", defaultValue: true, "Aiming next to plants of the same kind (planted, grown or still being planted), the grid continues their field: same lines and spacing, starting on the free spot next to them nearest your aim, and growing away from them. The snap key switches it while you play."); _snapKey = base.Config.Bind<KeyCode>("General", "Snap key", (KeyCode)291, "Turns lining up with fields on or off."); _fillOn = base.Config.Bind("General", "Fill field", defaultValue: false, "Instead of rows x columns, the grid is every free spot of the cultivated patch under your aim (up to the most plants per click): one click plants a whole field. The fill key switches it while you play."); _fillKey = base.Config.Bind<KeyCode>("General", "Fill key", (KeyCode)288, "Turns Fill field on or off."); _fillReach = base.Config.Bind("General", "Fill reach (m)", 40f, new ConfigDescription("Fill field plants no further than this from your aim.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 200f), Array.Empty<object>())); _rows = base.Config.Bind("Grid", "Rows", 2, new ConfigDescription("Rows of plants (away from you).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>())); _columns = base.Config.Bind("Grid", "Columns", 2, new ConfigDescription("Plants per row (to the right).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>())); _maxPlants = base.Config.Bind("Grid", "Most plants per click", 10000, new ConfigDescription("A grid never has more plants than this, whatever its size.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 40000), Array.Empty<object>())); _worldAligned = base.Config.Bind("Grid", "Line up with the world", defaultValue: true, "Rows run north and columns east (turned with the mouse wheel like any piece). Off: rows run away from you."); _tighter = base.Config.Bind("Grid", "Tighter spacing", defaultValue: false, "Crops stand closer together: just enough room to grow (1.1 x the room a plant needs, plus its own width) instead of twice the room.