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 RunicAgriculture v1.0.6
plugins/RunicAgriculture/RunicAgriculture.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; 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.Serialization.Json; using System.Runtime.Versioning; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Runic.Foundation.Core; using Runic.Localization; using RunicAgriculture.Core; using RunicAgriculture.Integration; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Runic Agriculture")] [assembly: AssemblyDescription("Bounded, validated planting patterns and modest crop harvesting for Valheim.")] [assembly: AssemblyCompany("Chazman")] [assembly: AssemblyProduct("Runic Agriculture")] [assembly: AssemblyFileVersion("1.0.5.0")] [assembly: AssemblyInformationalVersion("1.0.5")] [assembly: InternalsVisibleTo("RunicAgriculture.Tests")] [assembly: InternalsVisibleTo("RunicAgriculture.DedicatedHarness")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("1.0.5.0")] [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; } } } namespace Runic.Localization { internal sealed class LanguageCatalog { private readonly Dictionary<string, string> _english; private Dictionary<string, string> _selected = new Dictionary<string, string>(); private readonly Func<string, string> _read; private string _language; internal LanguageCatalog(string english, Func<string, string> read) { _english = Parse(english); _read = read; } internal static Dictionary<string, string> Parse(string json) { if (string.IsNullOrWhiteSpace(json)) { return new Dictionary<string, string>(); } if (json.Length > 2097152) { throw new InvalidDataException("Language file exceeds 2 MiB."); } DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(Dictionary<string, string>), new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true }); using MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json.TrimStart('\ufeff'))); return ((Dictionary<string, string>)dataContractJsonSerializer.ReadObject(stream)) ?? new Dictionary<string, string>(); } internal void Select(string language) { language = (string.IsNullOrWhiteSpace(language) ? "English" : language); if (string.Equals(language, _language, StringComparison.Ordinal)) { return; } _language = language; _selected = new Dictionary<string, string>(); if (language.IndexOfAny(new char[4] { '/', '\\', ':', '\0' }) >= 0 || language == "." || language == "..") { return; } try { _selected = Parse(_read(language)); } catch (Exception) { } } internal string Get(string key) { _english.TryGetValue(key, out var value); if (_selected.TryGetValue(key, out var value2) && !string.IsNullOrWhiteSpace(value2) && (value == null || SameFields(value, value2))) { return value2; } return value ?? key; } internal string English(string key) { if (!_english.TryGetValue(key, out var value)) { return key; } return value; } internal string TranslateEnglish(string text) { foreach (KeyValuePair<string, string> item in _english) { if (item.Value == text) { return Get(item.Key); } } return text; } internal string Format(string key, params object[] args) { _english.TryGetValue(key, out var value); string text = Get(key); if (value != null && !SameFields(value, text)) { text = value; } try { return string.Format(CultureInfo.CurrentCulture, text, args); } catch (FormatException) { try { return string.Format(CultureInfo.CurrentCulture, value ?? key, args); } catch (FormatException) { return value ?? key; } } } private static bool SameFields(string a, string b) { try { return Fields(a).SetEquals(Fields(b)); } catch (FormatException) { return false; } } private static HashSet<int> Fields(string text) { HashSet<int> hashSet = new HashSet<int>(); for (int i = 0; i < text.Length; i++) { if (text[i] == '}') { if (i + 1 >= text.Length || text[i + 1] != '}') { throw new FormatException(); } i++; } else { if (text[i] != '{') { continue; } if (i + 1 < text.Length && text[i + 1] == '{') { i++; continue; } int num = ++i; for (; i < text.Length && char.IsDigit(text[i]); i++) { } if (num == i || !int.TryParse(text.Substring(num, i - num), out var result)) { throw new FormatException(); } hashSet.Add(result); for (; i < text.Length && text[i] != '}'; i++) { if (text[i] == '{') { throw new FormatException(); } } if (i == text.Length) { throw new FormatException(); } } } return hashSet; } } internal static class RunicText { private static readonly Assembly Owner = typeof(RunicText).Assembly; private static readonly string Module = Owner.GetName().Name; private static readonly LanguageCatalog Catalog = Create(); private static LanguageCatalog Create() { using Stream stream = Owner.GetManifestResourceStream("Runic.Localization.English.json"); using StreamReader streamReader = ((stream == null) ? null : new StreamReader(stream)); return new LanguageCatalog(streamReader?.ReadToEnd() ?? "{}", ReadLanguage); } private static string ReadLanguage(string language) { string path = Path.Combine(Path.Combine(Path.GetDirectoryName(Owner.Location), "Translations", Module), language + ".json"); if (!File.Exists(path)) { return null; } return File.ReadAllText(path); } private static void SelectLanguage() { string language = "English"; try { Localization instance = Localization.instance; language = ((instance != null) ? instance.GetSelectedLanguage() : null) ?? "English"; } catch { } Catalog.Select(language); } internal static string Get(string key) { SelectLanguage(); return Catalog.Get(key); } internal static string English(string key) { return Catalog.English(key); } internal static string TranslateEnglish(string text) { SelectLanguage(); return Catalog.TranslateEnglish(text); } internal static string Format(string key, params object[] args) { SelectLanguage(); return Catalog.Format(key, args); } } } namespace Runic.Foundation.Core { public static class RunicIdentifier { public static bool IsValid(string value) { if (string.IsNullOrEmpty(value) || value.Length > 128) { return false; } bool flag = false; bool flag2 = false; foreach (char c in value) { if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) { flag = true; flag2 = false; continue; } switch (c) { case '-': if (!flag || flag2) { return false; } flag2 = true; break; case '.': if (!flag || flag2) { return false; } flag = false; flag2 = false; break; default: return false; } } if (flag) { return !flag2; } return false; } public static string Require(string value, string parameterName) { if (!IsValid(value)) { throw new ArgumentException("Runic identifiers must be lowercase dot-separated tokens containing only ASCII letters, digits, and internal hyphens.", parameterName); } return value; } } public sealed class InputChord : IEquatable<InputChord> { private readonly IReadOnlyList<string> _modifiers; public string DeviceId { get; } public string PrimaryControl { get; } public IReadOnlyList<string> Modifiers => _modifiers; public string CanonicalId { get; } public InputChord(string deviceId, string primaryControl, IEnumerable<string> modifiers = null) { DeviceId = RunicIdentifier.Require(deviceId, "deviceId"); PrimaryControl = RequireControl(primaryControl, "primaryControl"); string text = CanonicalizeControl(PrimaryControl); SortedDictionary<string, string> sortedDictionary = new SortedDictionary<string, string>(StringComparer.Ordinal); if (modifiers != null) { foreach (string modifier in modifiers) { string text2 = RequireControl(modifier, "modifiers"); string text3 = CanonicalizeControl(text2); if (string.Equals(text3, text, StringComparison.Ordinal)) { throw new ArgumentException("The primary control cannot also be a modifier.", "modifiers"); } if (sortedDictionary.ContainsKey(text3)) { throw new ArgumentException("Duplicate input modifier: " + text2, "modifiers"); } sortedDictionary.Add(text3, text2); } } string[] array = new string[sortedDictionary.Count]; int num = 0; foreach (string value in sortedDictionary.Values) { array[num++] = value; } _modifiers = Array.AsReadOnly(array); StringBuilder stringBuilder = new StringBuilder(DeviceId).Append(':'); foreach (string key in sortedDictionary.Keys) { stringBuilder.Append(key).Append('+'); } stringBuilder.Append(text); CanonicalId = stringBuilder.ToString(); } public bool Equals(InputChord other) { if (other != null) { return string.Equals(CanonicalId, other.CanonicalId, StringComparison.Ordinal); } return false; } public override bool Equals(object obj) { return Equals(obj as InputChord); } public override int GetHashCode() { return StringComparer.Ordinal.GetHashCode(CanonicalId); } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < _modifiers.Count; i++) { if (i > 0) { stringBuilder.Append(" + "); } stringBuilder.Append(_modifiers[i]); } if (_modifiers.Count > 0) { stringBuilder.Append(" + "); } return stringBuilder.Append(PrimaryControl).Append(" [").Append(DeviceId) .Append(']') .ToString(); } private static string RequireControl(string value, string parameterName) { if (string.IsNullOrWhiteSpace(value)) { throw new ArgumentException("An input control name is required.", parameterName); } string text = value.Trim(); if (text.Length > 64) { throw new ArgumentException("Input control names cannot exceed 64 characters.", parameterName); } string text2 = text; foreach (char c in text2) { if (char.IsControl(c) || c == ':' || c == '+' || c == '|') { throw new ArgumentException("The input control name contains a reserved character.", parameterName); } } if (CanonicalizeControl(text).Length == 0) { throw new ArgumentException("The input control name has no canonical characters.", parameterName); } return text; } private static string CanonicalizeControl(string value) { StringBuilder stringBuilder = new StringBuilder(value.Length); foreach (char c in value) { if (!char.IsWhiteSpace(c) && c != '_' && c != '-') { stringBuilder.Append(char.ToLowerInvariant(c)); } } return stringBuilder.ToString(); } } public sealed class KeybindingDescriptor { public string ModuleId { get; } public string BindingId { get; } public string QualifiedId => ModuleId + "/" + BindingId; public string DisplayName { get; } public InputChord Chord { get; } public string Context { get; } public KeybindingDescriptor(string moduleId, string bindingId, string displayName, InputChord chord, string context = "gameplay") { ModuleId = RunicIdentifier.Require(moduleId, "moduleId"); BindingId = RunicIdentifier.Require(bindingId, "bindingId"); Context = RunicIdentifier.Require(context, "context"); if (string.IsNullOrWhiteSpace(displayName)) { throw new ArgumentException("A keybinding display name is required.", "displayName"); } Chord = chord ?? throw new ArgumentNullException("chord"); DisplayName = displayName.Trim(); } } public sealed class KeybindingConflict { public InputChord Chord { get; } public IReadOnlyList<KeybindingDescriptor> Bindings { get; } internal KeybindingConflict(InputChord chord, IReadOnlyList<KeybindingDescriptor> bindings) { Chord = chord; Bindings = bindings; } } public enum KeybindingChangeKind { Registered, Unregistered } public sealed class KeybindingsChangedEventArgs : EventArgs { public KeybindingChangeKind Kind { get; } public KeybindingDescriptor Binding { get; } public KeybindingConflict Conflict { get; } internal KeybindingsChangedEventArgs(KeybindingChangeKind kind, KeybindingDescriptor binding, KeybindingConflict conflict) { Kind = kind; Binding = binding; Conflict = conflict; } } public sealed class KeybindingConflictRegistry { private sealed class BindingEntry { internal KeybindingDescriptor Binding { get; } internal long Token { get; } internal BindingEntry(KeybindingDescriptor binding, long token) { Binding = binding; Token = token; } } private readonly object _sync = new object(); private readonly Dictionary<string, BindingEntry> _byQualifiedId = new Dictionary<string, BindingEntry>(StringComparer.Ordinal); private readonly Dictionary<string, List<BindingEntry>> _byChord = new Dictionary<string, List<BindingEntry>>(StringComparer.Ordinal); private long _nextToken; public event EventHandler<KeybindingsChangedEventArgs> Changed; public KeybindingRegistration Register(KeybindingDescriptor binding) { if (binding == null) { throw new ArgumentNullException("binding"); } long token; KeybindingConflict conflict; lock (_sync) { if (_byQualifiedId.ContainsKey(binding.QualifiedId)) { throw new InvalidOperationException("A keybinding is already registered as '" + binding.QualifiedId + "'."); } if (_nextToken == long.MaxValue) { throw new InvalidOperationException("The keybinding registration token space is exhausted."); } token = ++_nextToken; BindingEntry bindingEntry = new BindingEntry(binding, token); _byQualifiedId.Add(binding.QualifiedId, bindingEntry); if (!_byChord.TryGetValue(binding.Chord.CanonicalId, out var value)) { value = new List<BindingEntry>(); _byChord.Add(binding.Chord.CanonicalId, value); } value.Add(bindingEntry); conflict = CreateConflictLocked(binding.Chord.CanonicalId); } RaiseChanged(new KeybindingsChangedEventArgs(KeybindingChangeKind.Registered, binding, conflict)); return new KeybindingRegistration(this, binding, token); } public bool Unregister(string moduleId, string bindingId) { RunicIdentifier.Require(moduleId, "moduleId"); RunicIdentifier.Require(bindingId, "bindingId"); return Unregister(moduleId + "/" + bindingId, (long?)null); } public bool TryGetBinding(string moduleId, string bindingId, out KeybindingDescriptor binding) { binding = null; if (!RunicIdentifier.IsValid(moduleId) || !RunicIdentifier.IsValid(bindingId)) { return false; } lock (_sync) { if (!_byQualifiedId.TryGetValue(moduleId + "/" + bindingId, out var value)) { return false; } binding = value.Binding; return true; } } public IReadOnlyList<KeybindingDescriptor> GetBindings() { lock (_sync) { List<KeybindingDescriptor> list = new List<KeybindingDescriptor>(_byQualifiedId.Count); foreach (BindingEntry value in _byQualifiedId.Values) { list.Add(value.Binding); } list.Sort((KeybindingDescriptor left, KeybindingDescriptor right) => StringComparer.Ordinal.Compare(left.QualifiedId, right.QualifiedId)); return list.AsReadOnly(); } } public IReadOnlyList<KeybindingConflict> GetConflicts() { lock (_sync) { List<KeybindingConflict> list = new List<KeybindingConflict>(); foreach (string key in _byChord.Keys) { KeybindingConflict keybindingConflict = CreateConflictLocked(key); if (keybindingConflict != null) { list.Add(keybindingConflict); } } list.Sort((KeybindingConflict left, KeybindingConflict right) => StringComparer.Ordinal.Compare(left.Chord.CanonicalId, right.Chord.CanonicalId)); return list.AsReadOnly(); } } public IReadOnlyList<KeybindingConflict> GetConflictsFor(string moduleId) { RunicIdentifier.Require(moduleId, "moduleId"); IReadOnlyList<KeybindingConflict> conflicts = GetConflicts(); List<KeybindingConflict> list = new List<KeybindingConflict>(); foreach (KeybindingConflict item in conflicts) { foreach (KeybindingDescriptor binding in item.Bindings) { if (string.Equals(binding.ModuleId, moduleId, StringComparison.Ordinal)) { list.Add(item); break; } } } return list.AsReadOnly(); } internal bool IsActive(string qualifiedId, long token) { lock (_sync) { BindingEntry value; return _byQualifiedId.TryGetValue(qualifiedId, out value) && value.Token == token; } } internal bool Unregister(string qualifiedId, long? requiredToken) { KeybindingDescriptor binding; KeybindingConflict conflict; lock (_sync) { if (!_byQualifiedId.TryGetValue(qualifiedId, out var entry) || (requiredToken.HasValue && entry.Token != requiredToken.Value)) { return false; } binding = entry.Binding; _byQualifiedId.Remove(qualifiedId); List<BindingEntry> list = _byChord[binding.Chord.CanonicalId]; list.RemoveAll((BindingEntry candidate) => candidate.Token == entry.Token); if (list.Count == 0) { _byChord.Remove(binding.Chord.CanonicalId); } conflict = CreateConflictLocked(binding.Chord.CanonicalId); } RaiseChanged(new KeybindingsChangedEventArgs(KeybindingChangeKind.Unregistered, binding, conflict)); return true; } private KeybindingConflict CreateConflictLocked(string chordId) { if (!_byChord.TryGetValue(chordId, out var value) || value.Count < 2) { return null; } List<KeybindingDescriptor> list = new List<KeybindingDescriptor>(value.Count); foreach (BindingEntry item in value) { list.Add(item.Binding); } list.Sort((KeybindingDescriptor left, KeybindingDescriptor right) => StringComparer.Ordinal.Compare(left.QualifiedId, right.QualifiedId)); return new KeybindingConflict(list[0].Chord, list.AsReadOnly()); } private void RaiseChanged(KeybindingsChangedEventArgs arguments) { EventHandler<KeybindingsChangedEventArgs> eventHandler = this.Changed; if (eventHandler == null) { return; } Delegate[] invocationList = eventHandler.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { EventHandler<KeybindingsChangedEventArgs> eventHandler2 = (EventHandler<KeybindingsChangedEventArgs>)invocationList[i]; try { eventHandler2(this, arguments); } catch (Exception) { } } } } public sealed class KeybindingRegistration : IDisposable { private readonly KeybindingConflictRegistry _registry; private readonly long _token; public KeybindingDescriptor Binding { get; } public bool IsActive => _registry.IsActive(Binding.QualifiedId, _token); internal KeybindingRegistration(KeybindingConflictRegistry registry, KeybindingDescriptor binding, long token) { _registry = registry; Binding = binding; _token = token; } public void Dispose() { _registry.Unregister(Binding.QualifiedId, _token); } } } namespace RunicAgriculture { internal static class AgricultureConfig { internal const int HardMaximumPreview = 1600; internal const int HardMaximumHarvest = 25; internal static ConfigEntry<bool> Enabled { get; private set; } internal static ConfigEntry<PlantPattern> Pattern { get; private set; } internal static ConfigEntry<AgricultureAlignment> Alignment { get; private set; } internal static ConfigEntry<bool> SnapToExistingRows { get; private set; } internal static ConfigEntry<int> Rows { get; private set; } internal static ConfigEntry<int> Columns { get; private set; } internal static ConfigEntry<float> Spacing { get; private set; } internal static ConfigEntry<float> LegacyCircleRadius { get; private set; } internal static ConfigEntry<bool> MirrorShape { get; private set; } internal static ConfigEntry<float> TrapezoidLeftPinch { get; private set; } internal static ConfigEntry<float> TrapezoidRightPinch { get; private set; } internal static ConfigEntry<float> NearbySeedChestRange { get; private set; } internal static ConfigEntry<InvalidPositionPolicy> InvalidPolicy { get; private set; } internal static ConfigEntry<ResourceShortfallPolicy> ResourcePolicy { get; private set; } internal static ConfigEntry<float> HarvestRadius { get; private set; } internal static ConfigEntry<int> MaximumHarvest { get; private set; } internal static ConfigEntry<bool> OfferReplantPreview { get; private set; } internal static ConfigEntry<bool> ShowHoverStatus { get; private set; } internal static ConfigEntry<bool> ShowContextualControls { get; private set; } internal static ConfigEntry<float> ControlBarScale { get; private set; } internal static ConfigEntry<bool> VerboseLogging { get; private set; } internal static ConfigEntry<KeyboardShortcut> ConfirmPattern { get; private set; } internal static ConfigEntry<KeyboardShortcut> CyclePattern { get; private set; } internal static ConfigEntry<KeyboardShortcut> AreaHarvest { get; private set; } internal static ConfigEntry<KeyboardShortcut> ConfirmReplant { get; private set; } internal static ConfigEntry<KeyboardShortcut> IncreaseRows { get; private set; } internal static ConfigEntry<KeyboardShortcut> DecreaseRows { get; private set; } internal static ConfigEntry<KeyboardShortcut> IncreaseColumns { get; private set; } internal static ConfigEntry<KeyboardShortcut> DecreaseColumns { get; private set; } internal static ConfigEntry<KeyboardShortcut> ToggleShapeSide { get; private set; } internal static ConfigEntry<KeyboardShortcut> DecreaseLeftPinch { get; private set; } internal static ConfigEntry<KeyboardShortcut> IncreaseLeftPinch { get; private set; } internal static ConfigEntry<KeyboardShortcut> DecreaseRightPinch { get; private set; } internal static ConfigEntry<KeyboardShortcut> IncreaseRightPinch { get; private set; } internal static ConfigEntry<bool> ControllerEnabled { get; private set; } internal static ConfigEntry<ValheimControllerAction> ControllerModifier { get; private set; } internal static ConfigEntry<ValheimControllerAction> ControllerConfirm { get; private set; } internal static ConfigEntry<ValheimControllerAction> ControllerCycle { get; private set; } internal static ConfigEntry<ValheimControllerAction> ControllerAreaHarvest { get; private set; } internal static ConfigEntry<ValheimControllerAction> ControllerPreviousEditorField { get; private set; } internal static ConfigEntry<ValheimControllerAction> ControllerNextEditorField { get; private set; } internal static ConfigEntry<ValheimControllerAction> ControllerDecreaseEditorValue { get; private set; } internal static ConfigEntry<ValheimControllerAction> ControllerIncreaseEditorValue { get; private set; } internal static ConfigEntry<bool> LegacyCircleRadiusMigrationApplied { get; private set; } internal static ConfigEntry<bool> GridAndCompactHudMigrationApplied { get; private set; } internal static void Bind(ConfigFile config) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Expected O, but got Unknown //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Expected O, but got Unknown //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Expected O, but got Unknown //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Expected O, but got Unknown //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Expected O, but got Unknown //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_0445: Expected O, but got Unknown //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04c3: Unknown result type (might be due to invalid IL or missing references) //IL_04c8: Unknown result type (might be due to invalid IL or missing references) //IL_04cb: Unknown result type (might be due to invalid IL or missing references) //IL_04d5: Invalid comparison between Unknown and I4 //IL_04ff: Unknown result type (might be due to invalid IL or missing references) //IL_04dc: Unknown result type (might be due to invalid IL or missing references) //IL_04e1: Unknown result type (might be due to invalid IL or missing references) //IL_0524: Unknown result type (might be due to invalid IL or missing references) //IL_0558: Unknown result type (might be due to invalid IL or missing references) //IL_058c: Unknown result type (might be due to invalid IL or missing references) //IL_05cb: Unknown result type (might be due to invalid IL or missing references) //IL_060a: Unknown result type (might be due to invalid IL or missing references) //IL_0649: Unknown result type (might be due to invalid IL or missing references) //IL_0688: Unknown result type (might be due to invalid IL or missing references) //IL_06c4: Unknown result type (might be due to invalid IL or missing references) //IL_0700: Unknown result type (might be due to invalid IL or missing references) //IL_073c: Unknown result type (might be due to invalid IL or missing references) //IL_0778: Unknown result type (might be due to invalid IL or missing references) //IL_07b4: Unknown result type (might be due to invalid IL or missing references) Enabled = config.Bind<bool>("General", "Enabled", true, RunicText.Get("text_062f2399ad55")); Pattern = config.Bind<PlantPattern>("Planting Pattern", "Pattern", PlantingGridPolicy.DefaultPattern, RunicText.Get("text_3380a0ba3316")); Alignment = config.Bind<AgricultureAlignment>("Planting Pattern", "Alignment", AgricultureAlignment.PlayerHeading, RunicText.Get("text_634d03807cc5")); SnapToExistingRows = config.Bind<bool>("Planting Pattern", "SnapToExistingRows", true, RunicText.Get("text_c6a150fcd483")); Rows = config.Bind<int>("Planting Pattern", "Rows", 5, new ConfigDescription(RunicText.Get("text_5f8df80ea007"), (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 256), Array.Empty<object>())); Columns = config.Bind<int>("Planting Pattern", "ColumnsOrPoints", 5, new ConfigDescription(RunicText.Get("text_a5e75c336fe7"), (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 256), Array.Empty<object>())); Spacing = config.Bind<float>("Planting Pattern", "SpacingMeters", 1.5f, new ConfigDescription(RunicText.Get("text_f0a386206418"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 6f), Array.Empty<object>())); LegacyCircleRadius = config.Bind<float>("Planting Pattern", "CircleRadiusMeters", 3f, new ConfigDescription(RunicText.Get("text_f61a244eba13"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 12f), Array.Empty<object>())); LegacyCircleRadiusMigrationApplied = config.Bind<bool>("Migrations", "LegacyCircleRadiusMappedToRowsAndColumns", false, RunicText.Get("text_44ec06e5158e")); if (!LegacyCircleRadiusMigrationApplied.Value) { bool saveOnConfigSet = config.SaveOnConfigSet; try { config.SaveOnConfigSet = false; if (ShouldMapLegacyCircleRadius(migrationApplied: false, Rows.Value, Columns.Value)) { int num = LegacyCircleDimension(LegacyCircleRadius.Value, Spacing.Value); if (Rows.Value != num) { Rows.Value = num; } if (Columns.Value != num) { Columns.Value = num; } } LegacyCircleRadiusMigrationApplied.Value = true; config.Save(); } finally { config.SaveOnConfigSet = saveOnConfigSet; } } MirrorShape = config.Bind<bool>("Planting Pattern", "MirrorShape", false, RunicText.Get("text_d2b9b602bf21")); TrapezoidLeftPinch = config.Bind<float>("Planting Pattern", "TrapezoidLeftPinch", 0.5f, new ConfigDescription(RunicText.Get("text_02a606cd059b"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); TrapezoidRightPinch = config.Bind<float>("Planting Pattern", "TrapezoidRightPinch", 0.5f, new ConfigDescription(RunicText.Get("text_a869d4816893"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); NearbySeedChestRange = config.Bind<float>("Planting Resources", "NearbyChestRangeMeters", 30f, new ConfigDescription(RunicText.Get("text_aa00bdc07966"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>())); InvalidPolicy = config.Bind<InvalidPositionPolicy>("Confirmation", "InvalidPositionPolicy", InvalidPositionPolicy.SkipInvalid, RunicText.Get("text_ea163e54008a")); ResourcePolicy = config.Bind<ResourceShortfallPolicy>("Confirmation", "ResourceShortfallPolicy", ResourceShortfallPolicy.TruncatePredictably, RunicText.Get("text_c6ffae0f23ea")); HarvestRadius = config.Bind<float>("Harvest", "RadiusMeters", 4f, new ConfigDescription(RunicText.Get("text_044c4dd6edbf"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 8f), Array.Empty<object>())); MaximumHarvest = config.Bind<int>("Harvest", "MaximumPlants", 25, new ConfigDescription(RunicText.Get("text_7317af1f94d6"), (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 25), Array.Empty<object>())); OfferReplantPreview = config.Bind<bool>("Harvest", "OfferConfirmedReplant", true, RunicText.Get("text_6cb55563a879")); ShowHoverStatus = config.Bind<bool>("Status", "ShowBeeAndCropStatus", true, RunicText.Get("text_fd8b538263fd")); ShowContextualControls = config.Bind<bool>("Status", "ShowContextualControls", true, RunicText.Get("text_feaaacf65721")); ControlBarScale = config.Bind<float>("Status", "ControlBarScale", 0.9f, new ConfigDescription(RunicText.Get("text_dbf41efd8026"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.75f, 1.75f), Array.Empty<object>())); GridAndCompactHudMigrationApplied = config.Bind<bool>("Migrations", "GridAndCompactBottomHudApplied", false, RunicText.Get("text_d678d2a41521")); ApplyGridAndCompactHudMigration(config); VerboseLogging = config.Bind<bool>("Diagnostics", "VerboseLogging", false, RunicText.Get("text_922bc33074a7")); ConfirmPattern = config.Bind<KeyboardShortcut>("Controls", "ConfirmPattern", new KeyboardShortcut((KeyCode)323, Array.Empty<KeyCode>()), RunicText.Get("text_bddae62a4ebb")); KeyboardShortcut value = ConfirmPattern.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey == 323) { value = ConfirmPattern.Value; if (!((KeyboardShortcut)(ref value)).Modifiers.Any()) { goto IL_0509; } } ConfirmPattern.Value = new KeyboardShortcut((KeyCode)323, Array.Empty<KeyCode>()); goto IL_0509; IL_0509: CyclePattern = config.Bind<KeyboardShortcut>("Controls", "CyclePattern", new KeyboardShortcut((KeyCode)111, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), RunicText.Get("text_944abf2e8819")); AreaHarvest = config.Bind<KeyboardShortcut>("Controls", "AreaHarvestModifierInteract", new KeyboardShortcut((KeyCode)101, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), RunicText.Get("text_f9d7a147a398")); ConfirmReplant = config.Bind<KeyboardShortcut>("Controls", "ConfirmReplant", new KeyboardShortcut((KeyCode)116, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), RunicText.Get("text_9bb76ce57f98")); IncreaseRows = config.Bind<KeyboardShortcut>("Pattern Editing Controls", "IncreaseRows", new KeyboardShortcut((KeyCode)273, (KeyCode[])(object)new KeyCode[2] { (KeyCode)308, (KeyCode)304 }), RunicText.Get("text_c5d12526d008")); DecreaseRows = config.Bind<KeyboardShortcut>("Pattern Editing Controls", "DecreaseRows", new KeyboardShortcut((KeyCode)274, (KeyCode[])(object)new KeyCode[2] { (KeyCode)308, (KeyCode)304 }), RunicText.Get("text_f4a62507405f")); IncreaseColumns = config.Bind<KeyboardShortcut>("Pattern Editing Controls", "IncreaseColumns", new KeyboardShortcut((KeyCode)275, (KeyCode[])(object)new KeyCode[2] { (KeyCode)308, (KeyCode)304 }), RunicText.Get("text_1dc2185a3a67")); DecreaseColumns = config.Bind<KeyboardShortcut>("Pattern Editing Controls", "DecreaseColumns", new KeyboardShortcut((KeyCode)276, (KeyCode[])(object)new KeyCode[2] { (KeyCode)308, (KeyCode)304 }), RunicText.Get("text_642dfed9cf66")); ToggleShapeSide = config.Bind<KeyboardShortcut>("Pattern Editing Controls", "ToggleShapeSide", new KeyboardShortcut((KeyCode)108, (KeyCode[])(object)new KeyCode[2] { (KeyCode)308, (KeyCode)304 }), RunicText.Get("text_acb7b0125402")); DecreaseLeftPinch = config.Bind<KeyboardShortcut>("Pattern Editing Controls", "DecreaseLeftTrapezoidPinch", new KeyboardShortcut((KeyCode)91, (KeyCode[])(object)new KeyCode[2] { (KeyCode)308, (KeyCode)304 }), RunicText.Get("text_1bf04d54db6f")); IncreaseLeftPinch = config.Bind<KeyboardShortcut>("Pattern Editing Controls", "IncreaseLeftTrapezoidPinch", new KeyboardShortcut((KeyCode)93, (KeyCode[])(object)new KeyCode[2] { (KeyCode)308, (KeyCode)304 }), RunicText.Get("text_af299d6064e1")); DecreaseRightPinch = config.Bind<KeyboardShortcut>("Pattern Editing Controls", "DecreaseRightTrapezoidPinch", new KeyboardShortcut((KeyCode)59, (KeyCode[])(object)new KeyCode[2] { (KeyCode)308, (KeyCode)304 }), RunicText.Get("text_891c491e9a0a")); IncreaseRightPinch = config.Bind<KeyboardShortcut>("Pattern Editing Controls", "IncreaseRightTrapezoidPinch", new KeyboardShortcut((KeyCode)39, (KeyCode[])(object)new KeyCode[2] { (KeyCode)308, (KeyCode)304 }), RunicText.Get("text_1a9700c0ea7b")); ControllerEnabled = config.Bind<bool>("Controller Controls", "Enabled", true, RunicText.Get("text_dfc9d3f71a47")); ControllerModifier = config.Bind<ValheimControllerAction>("Controller Controls", "ModifierAction", ValheimControllerAction.JoyAltKeys, RunicText.Get("text_dc4902cecbf6")); ControllerConfirm = config.Bind<ValheimControllerAction>("Controller Controls", "ConfirmAction", ValheimControllerAction.JoyPlace, RunicText.Get("text_5de612a71616")); ControllerCycle = config.Bind<ValheimControllerAction>("Controller Controls", "CyclePatternAction", ValheimControllerAction.JoyPrevSnap, RunicText.Get("text_d04b45d703bc")); ControllerAreaHarvest = config.Bind<ValheimControllerAction>("Controller Controls", "AreaHarvestAction", ValheimControllerAction.JoyUse, RunicText.Get("text_087da402a5f0")); ControllerPreviousEditorField = config.Bind<ValheimControllerAction>("Controller Pattern Editor", "PreviousEditorFieldAction", ValheimControllerAction.JoyDPadUp, RunicText.Get("text_eb40b0bfea5b")); ControllerNextEditorField = config.Bind<ValheimControllerAction>("Controller Pattern Editor", "NextEditorFieldAction", ValheimControllerAction.JoyDPadDown, RunicText.Get("text_734db65456d0")); ControllerDecreaseEditorValue = config.Bind<ValheimControllerAction>("Controller Pattern Editor", "DecreaseEditorValueAction", ValheimControllerAction.JoyDPadLeft, RunicText.Get("text_7c8c16085237")); ControllerIncreaseEditorValue = config.Bind<ValheimControllerAction>("Controller Pattern Editor", "IncreaseEditorValueAction", ValheimControllerAction.JoyDPadRight, RunicText.Get("text_0b2485e84dfa")); } internal static AgricultureControllerBindings CurrentControllerBindings() { return new AgricultureControllerBindings(ControllerModifier.Value, ControllerConfirm.Value, ControllerCycle.Value, ControllerAreaHarvest.Value, ControllerPreviousEditorField.Value, ControllerNextEditorField.Value, ControllerDecreaseEditorValue.Value, ControllerIncreaseEditorValue.Value); } internal static int LegacyCircleDimension(float radius, float spacing) { if (float.IsNaN(radius) || float.IsInfinity(radius) || radius <= 0f) { throw new ArgumentOutOfRangeException("radius"); } if (float.IsNaN(spacing) || float.IsInfinity(spacing) || spacing <= 0f) { throw new ArgumentOutOfRangeException("spacing"); } int num = (int)Math.Round(radius / spacing, MidpointRounding.AwayFromZero); return Math.Max(1, Math.Min(49, num * 2 + 1)); } internal static bool ShouldMapLegacyCircleRadius(bool migrationApplied, int rows, int columns) { if (!migrationApplied && rows == 5) { return columns == 5; } return false; } private static void ApplyGridAndCompactHudMigration(ConfigFile config) { if (GridAndCompactHudMigrationApplied.Value) { return; } bool saveOnConfigSet = config.SaveOnConfigSet; try { config.SaveOnConfigSet = false; Pattern.Value = PlantingGridPolicy.MigrateToDefaultGrid(migrationAlreadyApplied: false, Pattern.Value); if (Math.Abs(ControlBarScale.Value - 1f) < 0.0001f) { ControlBarScale.Value = 0.9f; } GridAndCompactHudMigrationApplied.Value = true; config.Save(); } finally { config.SaveOnConfigSet = saveOnConfigSet; } } } [BepInPlugin("chazman.RunicAgriculture", "Runic Agriculture", "1.0.5")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "chazman.RunicAgriculture"; public const string Name = "Runic Agriculture"; public const string Version = "1.0.5"; public const string ModuleId = "runic.agriculture"; public const string ProtocolVersion = "1.0"; private readonly List<KeybindingRegistration> _keybindingRegistrations = new List<KeybindingRegistration>(); private readonly KeybindingConflictRegistry _keybindings = new KeybindingConflictRegistry(); private Harmony _harmony; private AgricultureRuntime _runtime; internal static Plugin Instance { get; private set; } internal AgricultureRuntime Runtime => _runtime; internal ManualLogSource Log => ((BaseUnityPlugin)this).Logger; private void Awake() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown Instance = this; AgricultureConfig.Bind(((BaseUnityPlugin)this).Config); ((BaseUnityPlugin)this).Config.SettingChanged += OnSettingChanged; try { AgriculturePatternService patternService = new AgriculturePatternService(); _runtime = new AgricultureRuntime(patternService, ((BaseUnityPlugin)this).Logger); _harmony = new Harmony("chazman.RunicAgriculture"); _harmony.PatchAll(typeof(Plugin).Assembly); RegisterKeybindings(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Runic Agriculture v1.0.5 ready: bounded pattern preview, native owner-local planting, exact Pickable area harvest, replant offers, and live controls."); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Runic Agriculture configuration: " + _runtime.ConfigurationSummary())); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Runic Agriculture controls: " + _runtime.ControlSummary())); } catch (Exception ex) { ShutdownRuntime(); ((BaseUnityPlugin)this).Logger.LogError((object)("Runic Agriculture startup failed; vanilla agriculture remains unchanged. " + ex.GetType().Name + ": " + ex.Message)); } } private void OnDestroy() { ((BaseUnityPlugin)this).Config.SettingChanged -= OnSettingChanged; ShutdownRuntime(); Instance = null; } private void OnSettingChanged(object sender, SettingChangedEventArgs arguments) { try { object obj; if (arguments == null) { obj = null; } else { ConfigEntryBase changedSetting = arguments.ChangedSetting; obj = ((changedSetting != null) ? changedSetting.Definition : null); } ConfigDefinition val = (ConfigDefinition)obj; if (val == (ConfigDefinition)null || val.Section == "Controls" || val.Section == "Pattern Editing Controls" || val.Section == "Controller Controls" || val.Section == "Controller Pattern Editor") { RegisterKeybindings(); } string changedSetting2 = ((val == (ConfigDefinition)null) ? "unknown setting" : (val.Section + "/" + val.Key)); _runtime?.OnConfigurationChanged(changedSetting2); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Agriculture configuration refresh failed: " + ex.Message)); } } private void RegisterKeybindings() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_0100: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: 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) DisposeKeybindings(); RegisterKeybinding("confirm-pattern", "Confirm planting pattern", AgricultureConfig.ConfirmPattern.Value); RegisterKeybinding("cycle-pattern", "Cycle planting pattern", AgricultureConfig.CyclePattern.Value); RegisterKeybinding("area-harvest", "Area harvest", AgricultureConfig.AreaHarvest.Value); RegisterKeybinding("confirm-replant", "Confirm replant offer", AgricultureConfig.ConfirmReplant.Value); RegisterKeybinding("increase-rows", "Increase planting rows", AgricultureConfig.IncreaseRows.Value); RegisterKeybinding("decrease-rows", "Decrease planting rows", AgricultureConfig.DecreaseRows.Value); RegisterKeybinding("increase-columns", "Increase planting columns", AgricultureConfig.IncreaseColumns.Value); RegisterKeybinding("decrease-columns", "Decrease planting columns", AgricultureConfig.DecreaseColumns.Value); RegisterKeybinding("toggle-shape-side", "Switch planting shape side", AgricultureConfig.ToggleShapeSide.Value); RegisterKeybinding("decrease-left-pinch", "Widen trapezoid left edge", AgricultureConfig.DecreaseLeftPinch.Value); RegisterKeybinding("increase-left-pinch", "Pinch trapezoid left edge", AgricultureConfig.IncreaseLeftPinch.Value); RegisterKeybinding("decrease-right-pinch", "Widen trapezoid right edge", AgricultureConfig.DecreaseRightPinch.Value); RegisterKeybinding("increase-right-pinch", "Pinch trapezoid right edge", AgricultureConfig.IncreaseRightPinch.Value); ConfigEntry<bool> controllerEnabled = AgricultureConfig.ControllerEnabled; if (controllerEnabled != null && controllerEnabled.Value) { AgricultureControllerBindings agricultureControllerBindings = AgricultureConfig.CurrentControllerBindings(); if (!agricultureControllerBindings.TryValidate(out var problem)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Agriculture controller bindings were not registered: " + problem + ".")); return; } RegisterControllerBinding("controller-confirm", "Confirm planting/replant preview (controller)", agricultureControllerBindings.Confirm, agricultureControllerBindings.Modifier); RegisterControllerBinding("controller-cycle", "Cycle planting pattern (controller)", agricultureControllerBindings.Cycle, agricultureControllerBindings.Modifier); RegisterControllerBinding("controller-area-harvest", "Area harvest (controller)", agricultureControllerBindings.AreaHarvest, agricultureControllerBindings.Modifier); RegisterControllerControl("controller-editor-previous", "Previous planting setting (controller)", agricultureControllerBindings.PreviousEditorField); RegisterControllerControl("controller-editor-next", "Next planting setting (controller)", agricultureControllerBindings.NextEditorField); RegisterControllerControl("controller-editor-decrease", "Decrease planting setting (controller)", agricultureControllerBindings.DecreaseEditorValue); RegisterControllerControl("controller-editor-increase", "Increase planting setting (controller)", agricultureControllerBindings.IncreaseEditorValue); } } private void RegisterKeybinding(string id, string name, KeyboardShortcut shortcut) { //IL_0002: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0) { return; } List<string> list = new List<string>(); IEnumerable<KeyCode> modifiers = ((KeyboardShortcut)(ref shortcut)).Modifiers; if (modifiers != null) { foreach (KeyCode item in modifiers) { list.Add(((object)item/*cast due to .constrained prefix*/).ToString()); } } _keybindingRegistrations.Add(_keybindings.Register(new KeybindingDescriptor("runic.agriculture", id, name, new InputChord("keyboard", ((object)((KeyboardShortcut)(ref shortcut)).MainKey/*cast due to .constrained prefix*/).ToString(), list), "agriculture"))); } private void RegisterControllerBinding(string id, string name, ValheimControllerAction primary, ValheimControllerAction modifier) { _keybindingRegistrations.Add(_keybindings.Register(new KeybindingDescriptor("runic.agriculture", id, name, new InputChord("controller", primary.ToString(), new string[1] { modifier.ToString() }), "agriculture"))); } private void RegisterControllerControl(string id, string name, ValheimControllerAction primary) { _keybindingRegistrations.Add(_keybindings.Register(new KeybindingDescriptor("runic.agriculture", id, name, new InputChord("controller", primary.ToString(), Array.Empty<string>()), "agriculture"))); } private void ShutdownRuntime() { DisposeKeybindings(); try { _runtime?.Dispose(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Agriculture runtime cleanup failed: " + ex.Message)); } _runtime = null; try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Agriculture Harmony cleanup failed: " + ex2.Message)); } _harmony = null; } private void DisposeKeybindings() { for (int num = _keybindingRegistrations.Count - 1; num >= 0; num--) { try { _keybindingRegistrations[num].Dispose(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Keybinding cleanup failed: " + ex.Message)); } } _keybindingRegistrations.Clear(); } } } namespace RunicAgriculture.Integration { internal readonly struct AgricultureHintRow { internal string Key { get; } internal string Action { get; } internal AgricultureHintRow(string key, string action) { Key = key ?? string.Empty; Action = action ?? string.Empty; } } internal sealed class AgricultureControlBarContent { internal IReadOnlyList<AgricultureHintRow> Rows { get; } internal AgricultureControlBarContent(params AgricultureHintRow[] rows) { Rows = rows ?? Array.Empty<AgricultureHintRow>(); } } internal sealed class AgricultureControlBar : IDisposable { private readonly Dictionary<TMP_Text, string> _originalText = new Dictionary<TMP_Text, string>(); private GameObject _root; private Vector3 _originalScale; private bool _hasOriginalScale; internal bool Apply(KeyHints hints, AgricultureControlBarContent content, float requestedScale) { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: 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_0054: 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) GameObject val = (((Object)(object)hints != (Object)null) ? hints.m_buildHints : null); if ((Object)(object)val == (Object)null || content == null || content.Rows.Count == 0) { Restore(); return false; } if (_root != val) { Restore(); _root = val; _originalScale = val.transform.localScale; _hasOriginalScale = true; TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null && !_originalText.ContainsKey(componentsInChildren[i])) { _originalText.Add(componentsInChildren[i], componentsInChildren[i].text ?? string.Empty); } } } float num = Mathf.Clamp(requestedScale, 0.75f, 1.75f); val.transform.localScale = Vector3.Scale(_originalScale, new Vector3(num, num, num)); TMP_Text[] array = (TMP_Text[])(object)new TMP_Text[5] { (TMP_Text)hints.m_buildMenuKey, (TMP_Text)hints.m_buildRotateKey, (TMP_Text)hints.m_buildAlternativePlacingKey, (TMP_Text)hints.m_dodgeKey, (TMP_Text)hints.m_cycleSnapKey }; HashSet<TMP_Text> knownKeys = new HashSet<TMP_Text>(array.Where((TMP_Text value) => (Object)(object)value != (Object)null)); int num2 = 0; int num3 = Math.Min(array.Length, content.Rows.Count); for (int num4 = 0; num4 < num3; num4++) { TMP_Text val2 = array[num4]; if (!((Object)(object)val2 == (Object)null)) { val2.text = content.Rows[num4].Key; TMP_Text val3 = FindActionLabel(val2, val.transform, knownKeys); if ((Object)(object)val3 != (Object)null) { val3.text = content.Rows[num4].Action; } num2++; } } return num2 > 0; } internal void Restore() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair<TMP_Text, string> item in _originalText) { if ((Object)(object)item.Key != (Object)null) { item.Key.text = item.Value; } } if ((Object)(object)_root != (Object)null && _hasOriginalScale) { _root.transform.localScale = _originalScale; } _originalText.Clear(); _root = null; _hasOriginalScale = false; } public void Dispose() { Restore(); } private static TMP_Text FindActionLabel(TMP_Text key, Transform root, ISet<TMP_Text> knownKeys) { Transform parent = key.transform.parent; while ((Object)(object)parent != (Object)null) { TMP_Text[] componentsInChildren = ((Component)parent).GetComponentsInChildren<TMP_Text>(true); int num = 0; for (int i = 0; i < componentsInChildren.Length; i++) { if (knownKeys.Contains(componentsInChildren[i])) { num++; } } if (num == 1 && componentsInChildren.Length >= 2) { TMP_Text val = null; foreach (TMP_Text val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && val2 != key && !knownKeys.Contains(val2) && ((Object)(object)val == (Object)null || (val2.text?.Length ?? 0) > (val.text?.Length ?? 0))) { val = val2; } } if ((Object)(object)val != (Object)null) { return val; } } if (parent == root) { break; } parent = parent.parent; } return null; } } internal static class AgricultureInputConsumption { private static int _sampleFrame = -1; private static int _wheelFrame = -1; private static int _buildMenuFrame = -1; private static int _placeFrame = -1; internal static void BeginSample(int frame) { if (_sampleFrame != frame) { _sampleFrame = frame; _wheelFrame = -1; _buildMenuFrame = -1; _placeFrame = -1; } } internal static void ConsumeWheel(int frame) { _wheelFrame = frame; } internal static void ConsumeBuildMenu(int frame) { _buildMenuFrame = frame; } internal static void ConsumePlace(int frame) { _placeFrame = frame; } internal static bool ShouldSuppressWheel(int frame) { return _wheelFrame == frame; } internal static bool ShouldSuppressBuildMenu(string action, int frame) { if (_buildMenuFrame == frame) { return string.Equals(action, "BuildMenu", StringComparison.Ordinal); } return false; } internal static bool ShouldSuppressPlace(string action, int frame) { if (_placeFrame == frame) { return string.Equals(action, "Attack", StringComparison.Ordinal); } return false; } internal static void Reset() { _sampleFrame = -1; _wheelFrame = -1; _buildMenuFrame = -1; _placeFrame = -1; } } [HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")] internal static class AgricultureConsumedMouseWheelPatch { [HarmonyPriority(800)] [HarmonyBefore(new string[] { "chazman.RunicPrecisionBuildTool" })] private static bool Prefix(ref float __result) { if (!AgricultureInputConsumption.ShouldSuppressWheel(Time.frameCount)) { return true; } __result = 0f; return false; } } [HarmonyPatch(typeof(ZInput), "GetButtonDown", new Type[] { typeof(string) })] internal static class AgricultureConsumedBuildMenuPatch { [HarmonyPriority(800)] [HarmonyBefore(new string[] { "chazman.RunicPrecisionBuildTool" })] private static bool Prefix(string name, ref bool __result) { if (!AgricultureInputConsumption.ShouldSuppressBuildMenu(name, Time.frameCount) && !AgricultureInputConsumption.ShouldSuppressPlace(name, Time.frameCount)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(KeyHints), "UpdateHints")] internal static class AgricultureBuildHintsReplacementPatch { [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "chazman.RunicPrecisionBuildTool" })] private static void Postfix(KeyHints __instance) { try { Plugin.Instance?.Runtime?.ApplyBuildHintsReplacement(__instance); } catch (Exception ex) { Plugin instance = Plugin.Instance; if (instance != null) { instance.Log.LogError((object)("Agriculture build-hint replacement failed closed: " + ex)); } Plugin.Instance?.Runtime?.DisableForSession("agriculture.placement-failed"); } } } internal static class AgricultureInventoryPayloadComparison { internal static bool MatchesLoaded(byte[] persisted, byte[] loaded) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if (persisted == null || loaded == null || persisted.Length != loaded.Length) { return false; } if (Equal(persisted, loaded)) { return true; } try { ZPackage val = new ZPackage(persisted); int num = val.ReadInt(); if (num != 109) { return false; } int num2 = val.ReadUShort(); byte[] array = (byte[])persisted.Clone(); for (int i = 0; i < num2; i++) { int pos = val.GetPos(); ItemData.Load(val, (Item)num); Buffer.BlockCopy(BitConverter.GetBytes((int)((float)BitConverter.ToInt32(persisted, pos) * 0.01f * 100f)), 0, array, pos, 4); } return val.GetPos() == persisted.Length && Equal(array, loaded); } catch { return false; } } private static bool Equal(byte[] left, byte[] right) { for (int i = 0; i < left.Length; i++) { if (left[i] != right[i]) { return false; } } return true; } } internal sealed class AgricultureRuntime : IDisposable { private sealed class MutationScope : IDisposable { private AgricultureRuntime _owner; internal MutationScope(AgricultureRuntime owner) { _owner = owner; } public void Dispose() { AgricultureRuntime agricultureRuntime = Interlocked.Exchange(ref _owner, null); if (agricultureRuntime != null) { Interlocked.Exchange(ref agricultureRuntime._mutationActive, 0); } } } private sealed class PreviewSnapshot { internal string CropId { get; } internal Piece Piece { get; } internal Quaternion Rotation { get; } internal IReadOnlyList<Vector3> Positions { get; } internal bool IsReplant { get; } internal PreviewSnapshot(string cropId, Piece piece, Quaternion rotation, IReadOnlyList<Vector3> positions, bool isReplant) { //IL_0015: 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) CropId = cropId; Piece = piece; Rotation = rotation; Positions = positions; IsReplant = isReplant; } } private sealed class HarvestPickableCandidate { internal Pickable Pickable { get; } internal string PrefabName { get; } internal int PrefabHash { get; } internal ZDOID ZdoId { get; } internal Vector3 Position { get; } internal HarvestPickableCandidate(Pickable pickable, string prefabName, int prefabHash, ZDOID zdoId, Vector3 position) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) Pickable = pickable; PrefabName = prefabName; PrefabHash = prefabHash; ZdoId = zdoId; Position = position; } } private const int UnlimitedActions = 1000000; private readonly IAgriculturePatternService _patternService; private readonly ManualLogSource _log; private readonly ValheimPlacementValidator _validator = new ValheimPlacementValidator(); private readonly PreviewPool _previewPool = new PreviewPool(1600); private readonly ReplantConfirmation<Vector3> _replant = new ReplantConfirmation<Vector3>(25); private readonly Collider[] _alignmentHits = (Collider[])(object)new Collider[256]; private readonly Collider[] _harvestHits = (Collider[])(object)new Collider[160]; private readonly Dictionary<string, string> _matureToPlant = new Dictionary<string, string>(StringComparer.Ordinal); private readonly AgricultureControlBar _controlBar = new AgricultureControlBar(); private PreviewSnapshot _lastPreview; private bool _disabledForSession; private float _nextPreviewUpdate; private bool _controllerActionsVerified; private string _controllerPathSignature; private string _lastControllerProblem; private int _controllerHarvestRequestFrame = -1; private ControllerEditorField _controllerEditorField; private int _previewValidCount; private int _previewGroundValidCount; private int _previewTotalCount; private string _previewIssueSummary = string.Empty; private string _previewLimitSummary = string.Empty; private string _previewBatchActionSummary = string.Empty; private float _patternYawDegrees; private string _snapSummary = string.Empty; private int _mutationActive; private Piece _seedBudgetPiece; private Vector3 _seedBudgetPlayerPosition; private int _seedBudgetValue; private float _seedBudgetExpiresAt; internal bool IsOperational { get { if (!_disabledForSession) { return AgricultureConfig.Enabled?.Value ?? false; } return false; } } internal AgricultureRuntime(IAgriculturePatternService patternService, ManualLogSource log) { _patternService = patternService ?? throw new ArgumentNullException("patternService"); _log = log ?? throw new ArgumentNullException("log"); ValheimAccess.Verify(); } internal void DisableForSession(string reasonCode) { if (!_disabledForSession) { _disabledForSession = true; _lastPreview = null; _previewPool.Hide(); RestoreBuildHintsIfOwned(); AgricultureInputConsumption.Reset(); Message(Player.m_localPlayer, RunicText.Get("text_3a762c94e3df")); Publish(reasonCode, "Agriculture runtime disabled after an unexpected failure.", "Restart Valheim, then check BepInEx/LogOutput.log before using batch actions."); } } internal string ConfigurationSummary() { return AgricultureFeedbackText.Configuration(AgricultureConfig.Enabled.Value, AgricultureConfig.Pattern.Value, AgricultureConfig.Rows.Value, AgricultureConfig.Columns.Value, AgricultureConfig.Spacing.Value, 1600, AgricultureConfig.HarvestRadius.Value, AgricultureConfig.MaximumHarvest.Value); } internal string ControlSummary() { //IL_0131: 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_016f: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: 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_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0266: 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) AgricultureControllerBindings agricultureControllerBindings = AgricultureConfig.CurrentControllerBindings(); string problem; string text = ((!AgricultureConfig.ControllerEnabled.Value) ? RunicText.Get("text_612f1e2ad0e4") : (agricultureControllerBindings.TryValidate(out problem) ? (RunicText.Get("text_252fae9ff849") + agricultureControllerBindings.ConfirmChord + RunicText.Get("text_3defc7571ef8") + agricultureControllerBindings.CycleChord + RunicText.Get("text_acda834b8146") + agricultureControllerBindings.AreaHarvestChord + RunicText.Get("text_b680800588c3") + ControllerActionDisplay.Friendly(agricultureControllerBindings.PreviousEditorField) + "/" + ControllerActionDisplay.Friendly(agricultureControllerBindings.NextEditorField) + RunicText.Get("text_68cefe3c6e2e") + ControllerActionDisplay.Friendly(agricultureControllerBindings.DecreaseEditorValue) + "/" + ControllerActionDisplay.Friendly(agricultureControllerBindings.IncreaseEditorValue) + RunicText.Get("text_ad1cef288539")) : (RunicText.Get("text_7825ff7a51d1") + problem + ")"))); return RunicText.Get("text_adf0acef19b6") + RunicText.Get("text_3defc7571ef8") + ShortcutLabel(AgricultureConfig.CyclePattern.Value) + RunicText.Get("text_acda834b8146") + ShortcutLabel(AgricultureConfig.AreaHarvest.Value) + RunicText.Get("text_fc4e390f760b") + ShortcutLabel(AgricultureConfig.ConfirmReplant.Value) + RunicText.Get("text_04f7b5c5bdce") + ShortcutLabel(AgricultureConfig.DecreaseRows.Value) + "/" + ShortcutLabel(AgricultureConfig.IncreaseRows.Value) + RunicText.Get("text_0ab07c4fc640") + ShortcutLabel(AgricultureConfig.DecreaseColumns.Value) + "/" + ShortcutLabel(AgricultureConfig.IncreaseColumns.Value) + RunicText.Get("text_c10d0fc37680") + ShortcutLabel(AgricultureConfig.ToggleShapeSide.Value) + RunicText.Get("text_cb5ac47da1d8") + ShortcutLabel(AgricultureConfig.DecreaseLeftPinch.Value) + "/" + ShortcutLabel(AgricultureConfig.IncreaseLeftPinch.Value) + RunicText.Get("text_575e17559d2d") + ShortcutLabel(AgricultureConfig.DecreaseRightPinch.Value) + "/" + ShortcutLabel(AgricultureConfig.IncreaseRightPinch.Value) + RunicText.Get("text_6eb5aa39195e") + RunicText.Get("text_7a1256c4f855") + "; " + text + "."; } internal void OnConfigurationChanged(string changedSetting) { _lastPreview = null; _nextPreviewUpdate = 0f; _seedBudgetExpiresAt = 0f; _controllerEditorField = ControllerPatternEditor.Normalize(AgricultureConfig.Pattern.Value, _controllerEditorField); if (changedSetting != null && (changedSetting.StartsWith("Controller Controls/", StringComparison.Ordinal) || changedSetting.StartsWith("Controller Pattern Editor/", StringComparison.Ordinal))) { _controllerActionsVerified = false; _controllerPathSignature = null; _lastControllerProblem = null; } if (!IsOperational) { _previewPool.Hide(); } string text = ConfigurationSummary(); _log.LogInfo((object)("Runic Agriculture configuration changed (" + changedSetting + "): " + text)); _log.LogInfo((object)("Runic Agriculture controls after configuration change: " + ControlSummary())); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { Message(localPlayer, RunicText.Get("text_5b38984fd34d") + text + "."); } AgricultureControllerBindings agricultureControllerBindings = AgricultureConfig.CurrentControllerBindings(); if (AgricultureConfig.ControllerEnabled.Value && !agricultureControllerBindings.TryValidate(out var problem)) { ReportControllerProblem(localPlayer, problem); } } internal void ApplyBuildHintsReplacement(KeyHints hints) { GameObject val = (((Object)(object)hints != (Object)null) ? hints.m_buildHints : null); Player localPlayer = Player.m_localPlayer; if ((Object)(object)val == (Object)null || !IsPlantingControlContext(localPlayer)) { _controlBar.Restore(); return; } if (!val.activeInHierarchy) { _controlBar.Restore(); return; } bool controller = false; try { controller = ZInput.IsGamepadActive(); } catch (Exception) { } _controlBar.Apply(hints, BuildControlBarContent(localPlayer, controller), AgricultureConfig.ControlBarScale.Value); } private AgricultureControlBarContent BuildControlBarContent(Player player, bool controller) { //IL_01bd: Unknown result type (might be due to invalid IL or missing references) PlantPattern value = AgricultureConfig.Pattern.Value; Piece val = ((player != null) ? player.GetSelectedPiece() : null); string text = (((Object)(object)val != (Object)null) ? val.m_name : string.Empty); try { if (!string.IsNullOrEmpty(text) && Localization.instance != null) { text = Localization.instance.Localize(text); } } catch (Exception) { } if (string.IsNullOrWhiteSpace(text)) { text = "Selected crop"; } string text2 = ((value == PlantPattern.Row) ? 1 : AgricultureConfig.Rows.Value) + " rows × " + AgricultureConfig.Columns.Value + " columns"; string text3 = ((_lastPreview == null) ? "preview loading" : (_previewValidCount + "/" + _previewTotalCount + " ready" + ((_previewGroundValidCount > _previewValidCount) ? ("; red: " + (_previewGroundValidCount - _previewValidCount) + " missing planting resources") : string.Empty) + (string.IsNullOrEmpty(_previewIssueSummary) ? string.Empty : ("; amber: " + _previewIssueSummary)) + (string.IsNullOrEmpty(_previewLimitSummary) ? string.Empty : ("; " + _previewLimitSummary)) + (string.IsNullOrEmpty(_previewBatchActionSummary) ? string.Empty : ("; " + _previewBatchActionSummary)))); bool flag = IsReplantPreviewForSelection(player); if (!controller) { return new AgricultureControlBarContent(new AgricultureHintRow(flag ? ShortcutLabel(AgricultureConfig.ConfirmReplant.Value) : "Mouse-1", (flag ? "Replant " : "Plant ") + text + " • " + value.ToString() + " • " + text3), new AgricultureHintRow("Alt + Wheel ↓ / ↑", "Rows − / + " + ((value == PlantPattern.Row) ? "1 (Row pattern)" : AgricultureConfig.Rows.Value.ToString(CultureInfo.InvariantCulture))), new AgricultureHintRow("Shift + Wheel ↓ / ↑", "Columns − / + " + AgricultureConfig.Columns.Value), new AgricultureHintRow("Wheel", (_snapSummary.Length > 0) ? _snapSummary : ("Rotate " + _patternYawDegrees.ToString("0.#", CultureInfo.InvariantCulture) + "° • spacing " + AgricultureConfig.Spacing.Value.ToString("0.0", CultureInfo.InvariantCulture) + " m")), new AgricultureHintRow("Alt + Mouse-2 / Num 2", "Pattern " + value.ToString() + " • " + text2 + " • change / select basic Grid")); } AgricultureControllerBindings agricultureControllerBindings = AgricultureConfig.CurrentControllerBindings(); string problem = string.Empty; if (!AgricultureConfig.ControllerEnabled.Value || !EnsureControllerActions(player) || !agricultureControllerBindings.TryValidate(out problem)) { string action = (AgricultureConfig.ControllerEnabled.Value ? ("Controller Agriculture bindings unavailable" + (string.IsNullOrWhiteSpace(problem) ? "." : (": " + problem + "."))) : "Controller Agriculture controls are disabled."); return new AgricultureControlBarContent(new AgricultureHintRow("Mouse-1", "Plant " + text + " — " + text3), new AgricultureHintRow("Alt + Wheel ↓ / ↑", "Rows − / + " + AgricultureConfig.Rows.Value), new AgricultureHintRow("Shift + Wheel ↓ / ↑", "Columns − / + " + AgricultureConfig.Columns.Value), new AgricultureHintRow("Wheel", "Rotate • spacing " + AgricultureConfig.Spacing.Value.ToString("0.0", CultureInfo.InvariantCulture) + " m"), new AgricultureHintRow("Alt + Shift + Wheel", action)); } if (flag) { return new AgricultureControlBarContent(new AgricultureHintRow(ValheimAccess.ControllerChordLabel(agricultureControllerBindings, agricultureControllerBindings.Confirm), "Replant " + text + " — " + text3)); } _controllerEditorField = ControllerPatternEditor.Normalize(value, _controllerEditorField); string text4 = ControllerEditorFieldLabel(value, _controllerEditorField); string key = ValheimAccess.ControllerControlLabel(agricultureControllerBindings.PreviousEditorField) + " / " + ValheimAccess.ControllerControlLabel(agricultureControllerBindings.NextEditorField); string key2 = ValheimAccess.ControllerControlLabel(agricultureControllerBindings.DecreaseEditorValue) + " / " + ValheimAccess.ControllerControlLabel(agricultureControllerBindings.IncreaseEditorValue); return new AgricultureControlBarContent(new AgricultureHintRow(ValheimAccess.ControllerChordLabel(agricultureControllerBindings, agricultureControllerBindings.Confirm), "Plant " + text + " • " + value.ToString() + " • " + text3), new AgricultureHintRow(ValheimAccess.ControllerChordLabel(agricultureControllerBindings, agricultureControllerBindings.Cycle), "Pattern " + value.ToString() + " " + text2), new AgricultureHintRow(key, "Choose " + text4), new AgricultureHintRow(key2, "Adjust " + text4), new AgricultureHintRow("", (_snapSummary.Length > 0) ? _snapSummary : ("Spacing " + AgricultureConfig.Spacing.Value.ToString("0.0", CultureInfo.InvariantCulture) + " m"))); } internal void TickInput(Player player) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !((Character)player).IsOwner()) { return; } AgricultureInputConsumption.BeginSample(Time.frameCount); AgricultureControllerCollisionGuard.Poll(); if (!ValheimAccess.PlayerTakesInput(player)) { return; } bool keyboardCycle = ValheimAccess.ShortcutDown(AgricultureConfig.CyclePattern.Value); bool keyboardConfirmPattern = false; bool keyboardConfirmReplant = ValheimAccess.ShortcutDown(AgricultureConfig.ConfirmReplant.Value); PatternEditAction patternEditAction = ReadPatternEditAction(); int num = 0; bool flag = IsPlantPiece(player.GetSelectedPiece()); int num2; int num3; if (flag) { num2 = (IsPlantingControlContext(player) ? 1 : 0); if (num2 != 0) { num3 = ((!IsReplantPreviewForSelection(player)) ? 1 : 0); goto IL_008d; } } else { num2 = 0; } num3 = 0; goto IL_008d; IL_008d: bool flag2 = (byte)num3 != 0; PlantPattern? plantPattern = null; if (num2 != 0) { bool flag3 = ValheimAccess.KeyHeld((KeyCode)308, (KeyCode)307); bool flag4 = ValheimAccess.KeyHeld((KeyCode)304, (KeyCode)303); bool flag5 = ValheimAccess.KeyHeld((KeyCode)306, (KeyCode)305); if (flag2) { float num4 = ValheimAccess.MouseWheel(); AgricultureWheelTarget agricultureWheelTarget = AgricultureWheelRouter.Resolve(flag3, flag4, flag5, num4); if (agricultureWheelTarget != AgricultureWheelTarget.None) { AgricultureInputConsumption.ConsumeWheel(Time.frameCount); if (agricultureWheelTarget == AgricultureWheelTarget.Rotation) { num = ((num4 > 0f) ? 1 : (-1)); } else { patternEditAction = AgricultureWheelRouter.ToEditAction(agricultureWheelTarget, num4 > 0f); } } if (flag3 && !flag4 && !flag5 && ValheimAccess.ButtonDown("BuildMenu")) { AgricultureInputConsumption.ConsumeBuildMenu(Time.frameCount); keyboardCycle = true; } if (!flag3 && !flag4 && !flag5 && TryReadDirectPattern(out var pattern)) { plantPattern = pattern; } } if (!flag3 && !flag4 && !flag5 && ValheimAccess.ButtonDown("Attack")) { AgricultureInputConsumption.ConsumePlace(Time.frameCount); if (IsReplantPreviewForSelection(player)) { keyboardConfirmReplant = true; } else { keyboardConfirmPattern = true; } } } bool num5 = num2 != 0 && EnsureControllerActions(player); AgricultureControllerBindings agricultureControllerBindings = AgricultureConfig.CurrentControllerBindings(); bool flag6 = num5 && ValheimAccess.ControllerButtonHeldRaw(agricultureControllerBindings.Modifier); bool flag7 = flag6 && ValheimAccess.ControllerButtonDownRaw(agricultureControllerBindings.Cycle); bool flag8 = flag6 && ValheimAccess.ControllerButtonDownRaw(agricultureControllerBindings.Confirm); bool flag9 = num5 && !flag6 && flag2 && ValheimAccess.ControllerButtonDownRaw(agricultureControllerBindings.PreviousEditorField); bool flag10 = num5 && !flag6 && flag2 && ValheimAccess.ControllerButtonDownRaw(agricultureControllerBindings.NextEditorField); bool flag11 = num5 && !flag6 && flag2 && ValheimAccess.ControllerButtonDownRaw(agricultureControllerBindings.DecreaseEditorValue); bool flag12 = num5 && !flag6 && flag2 && ValheimAccess.ControllerButtonDownRaw(agricultureControllerBindings.IncreaseEditorValue); RoutedAgricultureAction routedAgricultureAction = AgricultureActionRouter.Resolve(new AgricultureInputFrame(keyboardCycle, keyboardConfirmPattern, keyboardConfirmReplant, flag7, flag8, _lastPreview != null && _lastPreview.IsReplant)); if (patternEditAction == PatternEditAction.None && num == 0 && routedAgricultureAction == RoutedAgricultureAction.None && !plantPattern.HasValue && !flag9 && !flag10 && !flag11 && !flag12) { return; } Trace("input routed to " + ((num != 0) ? "RotatePattern" : ((patternEditAction != PatternEditAction.None) ? patternEditAction.ToString() : routedAgricultureAction.ToString())) + ((flag7 || flag8 || flag9 || flag10 || flag11 || flag12) ? " from controller" : " from keyboard") + "."); if (!IsOperational) { Message(player, _disabledForSession ? RunicText.Get("text_de65c7b74bf8") : RunicText.Get("text_ec653f57b1bf")); } else if (!flag) { Message(player, RunicText.Get("text_83915513d3f8")); } else { if ((flag7 && !TryCaptureControllerGesture(player, agricultureControllerBindings.Cycle)) || (flag8 && !TryCaptureControllerGesture(player, agricultureControllerBindings.Confirm)) || (flag9 && !TryCaptureControllerEditorControl(player, agricultureControllerBindings.PreviousEditorField)) || (flag10 && !TryCaptureControllerEditorControl(player, agricultureControllerBindings.NextEditorField)) || (flag11 && !TryCaptureControllerEditorControl(player, agricultureControllerBindings.DecreaseEditorValue)) || (flag12 && !TryCaptureControllerEditorControl(player, agricultureControllerBindings.IncreaseEditorValue))) { return; } if (flag9 || flag10) { _controllerEditorField = ControllerPatternEditor.Move(AgricultureConfig.Pattern.Value, _controllerEditorField, flag10 ? 1 : (-1)); return; } if (flag11 || flag12) { patternEditAction = ControllerPatternEditor.ToEditAction(ControllerPatternEditor.Normalize(AgricultureConfig.Pattern.Value, _controllerEditorField), flag12); } if (num != 0) { RotatePattern(player, num); return; } if (patternEditAction != PatternEditAction.None) { Piece selectedPiece = player.GetSelectedPiece(); string b = PrefabIdentity.Of((selectedPiece != null) ? ((Component)selectedPiece).gameObject : null); if ((_lastPreview != null && _lastPreview.IsReplant) || (_replant.IsPending && string.Equals(_replant.CropId, b, StringComparison.Ordinal))) { Message(player, RunicText.Get("text_78a3824ca6e7")); } else { ApplyPatternEdit(player, patternEditAction); } return; } if (plantPattern.HasValue) { SetPattern(player, plantPattern.Value, "numpad"); return; } switch (routedAgricultureAction) { case RoutedAgricultureAction.CyclePattern: CyclePattern(player); break; case RoutedAgricultureAction.ConfirmReplant: ConfirmReplant(player); break; default: ConfirmPattern(player); break; } } } internal bool IsAreaHarvestRequested(Player player, GameObject targetObject) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) Pickable target = FindPickable(targetObject); if (!CanOfferAreaHarvest(player, target)) { return false; } if (ValheimAccess.ShortcutDown(AgricultureConfig.AreaHarvest.Value)) { return true; } if (!AgricultureConfig.ControllerEnabled.Value || !EnsureControllerActions(player)) { return false; } AgricultureControllerBindings agricultureControllerBindings = AgricultureConfig.CurrentControllerBindings(); int num; if (ValheimAccess.ControllerButtonHeldRaw(agricultureControllerBindings.Modifier)) { num = (ValheimAccess.ControllerButtonDownRaw(agricultureControllerBindings.AreaHarvest) ? 1 : 0); if (num != 0) { _controllerHarvestRequestFrame = Time.frameCount; } } else { num = 0; } return (byte)num != 0; } internal string HarvestControlHint() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) string text = ShortcutLabel(AgricultureConfig.AreaHarvest.Value); if (!AgricultureConfig.ControllerEnabled.Value) { return text; } AgricultureControllerBindings agricultureControllerBindings = AgricultureConfig.CurrentControllerBindings(); if (!EnsureControllerActions(Player.m_localPlayer) || !agricultureControllerBindings.TryValidate(out var _)) { return text; } return text + RunicText.Get("text_e1a3e78cb5c8") + agricultureControllerBindings.AreaHarvestChord; } internal void UpdatePreview(Player player) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_0129: 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_0257: 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_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_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) if (!IsOperational || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !((Character)player).IsOwner()) { _lastPreview = null; ClearControlBarPreview(); _previewPool.Hide(); return; } Piece selectedPiece = player.GetSelectedPiece(); GameObject placementGhost = ValheimAccess.GetPlacementGhost(player); if (!IsPlantPiece(selectedPiece) || (Object)(object)placementGhost == (Object)null || !placementGhost.activeInHierarchy) { _lastPreview = null; ClearControlBarPreview(); _previewPool.Hide(); } else { if (Time.unscaledTime < _nextPreviewUpdate) { return; } float num = MinimumSpacingFor(selectedPiece); if (AgricultureConfig.Spacing.Value < num) { AgricultureConfig.Spacing.Value = num; } string text = PrefabIdentity.Of(((Component)selectedPiece).gameObject); Quaternion val = ResolveAlignment(player, selectedPiece, placementGhost.transform.position); ExistingRowGrid? snappedGrid = null; _snapSummary = string.Empty; if (!_replant.IsPending && (AgricultureConfig.SnapToExistingRows.Value || AgricultureConfig.Alignment.Value == AgricultureAlignment.ExistingCropRow) && !ValheimAccess.KeyHeld((KeyCode)306, (KeyCode)305) && TryFindExistingGrid(selectedPiece, placementGhost.transform.position, val, num, out var grid)) { snappedGrid = grid; val = Quaternion.LookRotation(new Vector3((float)grid.Forward.Right, 0f, (float)grid.Forward.Forward), Vector3.up); _snapSummary = "Snapped " + grid.Spacing.ToString("0.##", CultureInfo.InvariantCulture) + " × " + grid.RowSpacing.ToString("0.##", CultureInfo.InvariantCulture) + " m • Ctrl: free placement"; } List<Vector3> list = BuildRequestedPositions(player, selectedPiece, placementGhost.transform.position, val, text, snappedGrid); if (list.Count == 0) { _nextPreviewUpdate = Time.unscaledTime + 0.1f; _lastPreview = null; ClearControlBarPreview(); _previewPool.Hide(); return; } bool isReplant = _replant.IsPending && string.Equals(_replant.CropId, text, StringComparison.Ordinal); List<RuntimePreviewPosition> list2 = BuildValidatedPreview(player, selectedPiece, list, val); _lastPreview = new PreviewSnapshot(text, selectedPiece, val, list, isReplant); _previewTotalCount = list2.Count; _previewValidCount = 0; _previewGroundValidCount = 0; Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal); for (int i = 0; i < list2.Count; i++) { RuntimePreviewPosition runtimePreviewPosition = list2[i]; if (runtimePreviewPosition.IsGroundValid) { _previewGroundValidCount++; if (runtimePreviewPosition.IsValid) { _previewValidCount++; } } else { string key = runtimePreviewPosition.ReasonCode ?? "agriculture.placement-failed"; dictionary.TryGetValue(key, out var value); dictionary[key] = value + 1; } } _previewIssueSummary = PreviewIssueSummary(dictionary); _previewBatchActionSummary = BatchActionIssue(player, selectedPiece); _previewPool.Show(placementGhost, list2); _nextPreviewUpdate = Time.unscaledTime + PreviewRefreshInterval(list2.Count); } } internal bool TryAreaHarvest(Player player, GameObject targetObject) { //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: 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) if (!IsOperational || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !((Character)player).IsOwner()) { return false; } bool flag = _controllerHarvestRequestFrame == Time.frameCount; _controllerHarvestRequestFrame = -1; Pickable target = FindPickable(targetObject); if (!CanOfferAreaHarvest(player, target)) { Trace("area harvest preserved the original interaction because the targeted Pickable was unavailable or access was denied."); return false; } if (!TryCaptureHarvestCandidate(target, out var aimed)) { if ((Object)(object)target != (Object)null) { Message(player, RunicText.Get("text_3a42974b5c83")); } Trace("area harvest preserved the original interaction because the targeted Pickable did not satisfy the live network/availability contract."); return false; } if (flag && !TryCaptureControllerGesture(player, AgricultureConfig.CurrentControllerBindings().AreaHarvest)) { return false; } string prefabName = aimed.PrefabName; string text = FindPlantForMature(prefabName); float num = Mathf.Clamp(AgricultureConfig.HarvestRadius.Value, 1f, 8f); int num2 = Mathf.Clamp(AgricultureConfig.MaximumHarvest.Value, 1, 25); int num3 = Physics.OverlapSphereNonAlloc(((Component)target).transform.position, num, _harvestHits, -1, (QueryTriggerInteraction)2); HashSet<Pickable> hashSet = new HashSet<Pickable>(); List<HarvestPickableCandidate> list = new List<HarvestPickableCandidate>(Math.Min(num3 + 1, _harvestHits.Length + 1)); hashSet.Add(target); list.Add(aimed); for (int i = 0; i < Math.Min(num3, _harvestHits.Length); i++) { Collider val = _harvestHits[i]; _harvestHits[i] = null; Pickable val2 = FindPickable(((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null); if (!((Object)(object)val2 == (Object)null) && hashSet.Add(val2) && TryCaptureHarvestCandidate(val2, out var candidate) && HarvestPickableBatchPolicy.IsExactPrefab(aimed.PrefabName, aimed.PrefabHash, candidate.PrefabName, candidate.PrefabHash)) { list.Add(candidate); } } list.Sort(delegate(HarvestPickableCandidate left, HarvestPickableCandidate right) { //IL_000f: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_0067: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) bool leftIsAimed = left.Pickable == target; Vector3 val4 = left.Position - aimed.Position; float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude; ZDOID zdoId = left.ZdoId; long userID = ((ZDOID)(ref zdoId)).UserID; zdoId = left.ZdoId; uint iD = ((ZDOID)(ref zdoId)).ID; bool rightIsAimed = right.Pickable == target; val4 = right.Position - aimed.Position; float sqrMagnitude2 = ((Vector3)(ref val4)).sqrMagnitude; zdoId = right.ZdoId; long userID2 = ((ZDOID)(ref zdoId)).UserID; zdoId = right.ZdoId; return HarvestPickableBatchPolicy.Compare(leftIsAimed, sqrMagnitude, userID, iD, rightIsAimed, sqrMagnitude2, userID2, ((ZDOID)(ref zdoId)).ID); }); List<Vector3> list2 = new List<Vector3>(num2); int num4 = 0; bool flag2 = false; for (int num5 = 0; num5 < list.Count; num5++) { if (num4 >= num2) { break; } if (!TryCaptureHarvestCandidate(list[num5].Pickable, out var candidate2) || !HarvestPickableBatchPolicy.IsExactPrefab(aimed.PrefabName, aimed.PrefabHash, candidate2.PrefabName, candidate2.PrefabHash)) { continue; } Vector3 val3 = candidate2.Position - aimed.Position; if (!(((Vector3)(ref val3)).sqrMagnitude > num * num)) { if (!PrivateArea.CheckAccess(candidate2.Position, 0f, false, false)) { flag2 |= candidate2.Pickable == target; continue; } candidate2.Pickable.Interact((Humanoid)(object)player, false, false); list2.Add(candidate2.Position); num4++; } } if (num4 == 0) { Message(player, RunicText.Get("text_694c44f70d6e")); Trace("area harvest found candidates but sent no permitted pick requests; " + (flag2 ? "the aimed Pickable was ward-denied." : "the original interaction remains available.")); return flag2; } bool authorized = PrivateArea.CheckAccess(aimed.Position, 0f, false, false); if (HarvestPickableBatchPolicy.OffersReplant(AgricultureConfig.OfferReplantPreview.Value, authorized, text)) { _replant.Offer(text, list2); Message(player, RunicText.Get("text_afcd0a95f11d") + num4 + RunicText.Get("text_26ac88dd11cc") + ShortcutLabel(AgricultureConfig.ConfirmReplant.Value) + (AgricultureConfig.ControllerEnabled.Value ? (RunicText.Get("text_e1a3e78cb5c8") + AgricultureConfig.CurrentControllerBindings().ConfirmChord) : string.Empty) + "."); } else { _replant.Clear(); Message(player, RunicText.Get("text_afcd0a95f11d") + num4 + RunicText.Get("text_1fd3582a75de")); } Trace("area harvest sent " + num4 + " owner-validated pick request(s) for '" + prefabName + "'."); return true; } internal bool CanOfferAreaHarvest(Player player, Pickable target) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (!IsOperational || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !((Character)player).IsOwner() || (Object)(object)target == (Object)null || !TryCaptureHarvestCandidate(target, out var candidate)) { return false; } return HarvestPickableBatchPolicy.AllowsAreaHarvest(PrivateArea.CheckAccess(candidate.Position, 0f, false, false)); } public void Dispose() { Interlocked.Exchange(ref _mutationActive, 0); _lastPreview = null; ClearControlBarPreview(); _replant.Clear(); _controllerHarvestRequestFrame = -1; RestoreBuildHintsIfOwned(); AgricultureInputConsumption.Reset(); AgricultureControllerCollisionGuard.Reset(); _controlBar.Dispose(); _previewPool.Dispose(); NearbySeedContainerIndex.Clear(); } private void CyclePattern(Player player) { SetPattern(player, PatternEditor.Next(AgricultureConfig.Pattern.Value), "cycle"); } private void SetPattern(Player player, PlantPattern pattern, string source) { if (Enum.IsDefined(typeof(PlantPattern), pattern)) { AgricultureConfig.Pattern.Value = pattern; _controllerEditorField = ControllerPatternEditor.Normalize(pattern, _controllerEditorField); Trace("planting pattern selected as " + pattern.ToString() + " from " + source + "."); } } private static PatternEditAction ReadPatternEditAction() { //IL_0005: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (ValheimAccess.ShortcutDown(AgricultureConfig.IncreaseRows.Value)) { return PatternEditAction.IncreaseRows; } if (ValheimAccess.ShortcutDown(AgricultureConfig.DecreaseRows.Value)) { return PatternEditAction.DecreaseRows; } if (ValheimAccess.ShortcutDown(AgricultureConfig.IncreaseColumns.Value)) { return PatternEditAction.IncreaseColumns; } if (ValheimAccess.ShortcutDown(AgricultureConfig.DecreaseColumns.Value)) { return PatternEditAction.DecreaseColumns; } if (ValheimAccess.ShortcutDown(AgricultureConfig.ToggleShapeSide.Value)) { return PatternEditAction.ToggleSide; } if (ValheimAccess.ShortcutDown(AgricultureConfig.DecreaseLeftPinch.Value)) { return PatternEditAction.DecreaseLeftPinch; } if (ValheimAccess.ShortcutDown(AgricultureConfig.IncreaseLeftPinch.Value)) { return PatternEditAction.IncreaseLeftPinch; } if (ValheimAccess.ShortcutDown(AgricultureConfig.DecreaseRightPinch.Value)) { return PatternEditAction.DecreaseRightPinch; } if (ValheimAccess.ShortcutDown(AgricultureConfig.IncreaseRightPinch.Value)) { return PatternEditAction.IncreaseRightPinch; } return PatternEditAction.None; } private void RotatePattern(Player player, int direction) { float num = ValheimAccess.PlaceRotationDegrees(player); if (float.IsNaN(num) || float.IsInfinity(num) || num <= 0f) { num = 22.5f; } _patternYawDegrees = Mathf.Repeat(_patternYawDegrees + ((direction > 0) ? num : (0f - num)), 360f); _lastPreview = null; _nextPreviewUpdate = 0f; Message(player, RunicText.Get("text_e8923015fc07") + _patternYawDegrees.ToString("0.#", CultureInfo.InvariantCulture) + "°."); } private void ApplyPatternEdit(Player player, PatternEditAction action) { PlantPattern value = AgricultureConfig.Pattern.Value; PatternEditState patternEditState = new PatternEditState(AgricultureConfig.Rows.Value, AgricultureConfig.Columns.Value, AgricultureConfig.MirrorShape.Value, AgricultureConfig.TrapezoidLeftPinch.Value, AgricultureConfig.TrapezoidRightPinch.Value, AgricultureConfig.Spacing.Value); PatternEditState patternEditState2 = PatternEditor.Apply(value, patternEditState, action); float num = MinimumSpacingFor(player.GetSelectedPiece()); if (patternEditState2.Spacing < (double)num) { patternEditState2 = new PatternEditState(patternEditState2.Rows, patternEditState2.Columns, patternEditState2.Mirrored, patternEditState2.LeftPinch, patternEditState2.RightPinch, num); } if (patternEditState2.Equals(patternEditState)) { string text = ((value == PlantPattern.Row && (action == PatternEditAction.IncreaseRows || action == PatternEditAction.DecreaseRows)) ? "Row has one forward row; use the column controls to change its length." : ((action == PatternEditAction.ToggleSide && !PatternEditor.SupportsMirror(value)) ? (value.ToString() + " is symmetric; side switching applies to RightTriangle, HalfCircle, and Trapezoid.") : (((action == PatternEditAction.DecreaseLeftPinch || action == PatternEditAction.IncreaseLeftPinch || action == PatternEditAction.DecreaseRightPinch || action == PatternEditAction.IncreaseRightPinch) && value != PlantPattern.Trapezoid) ? "Independent taper controls apply only to Trapezoid." : ((action == PatternEditAction.DecreaseSpacing && patternEditState.Spacing <= (double)num) ? ("That crop requires at least " + num.ToString("0.0", CultureInfo.InvariantCulture) + "m spacing.") : "That pattern setting is already at its safe limit.")))); Message(player, RunicText.Get("text_9650c9ad5863") + text); return; } if (patternEditState2.Rows != patternEditState.Rows) { AgricultureConfig.Rows.Value = patternEditState2.Rows; } else if (patternEditState2.Columns != patternEditState.Columns) { AgricultureConfig.Columns.Value = patternEditState2.Columns; } else if (patternEditState2.Mirrored != patternEditState.Mirrored) { AgricultureConfig.MirrorShape.Value = patternEditState2.Mirrored; } else if (!patternEditState2.LeftPinch.Equals(patternEditState.LeftPinch)) { AgricultureConfig.TrapezoidLeftPinch.Value = (float)patternEditState2.LeftPinch; } else if (!patternEditState2.RightPinch.Equals(patternEditState.RightPinch)) { AgricultureConfig.TrapezoidRightPinch.Value = (float)patternEditState2.RightPinch; } else if (!patternEditState2.Spacing.Equals(patternEditState.Spacing)) { AgricultureConfig.Spacing.Value = (float)patternEditState2.Spacing; } string text2 = value.ToString() + " " + ((value == PlantPattern.Row) ? (patternEditState2.Columns + " columns") : (patternEditState2.Rows + "x" + patternEditState2.Columns)); if (PatternEditor.SupportsMirror(value)) { text2 = text2 + ", " + PatternEditor.OrientationLabel(value, patternEditState2.Mirrored).ToLowerInvariant(); } if (value == PlantPattern.Trapezoid) { text2 = text2 + ", taper L " + Mathf.RoundToInt((float)patternEditState2.LeftPinch * 100f) + "% / R " + Mathf.RoundToInt((float)patternEditState2.RightPinch * 100f) + "%"; } text2 = text2 + ", spacing " + patternEditState2.Spacing.ToString("0.0", CultureInfo.InvariantCulture) + "m"; Message(player, RunicText.Get("text_9650c9ad5863") + text2 + "."); Trace("live pattern edit " + action.ToString() + " applied to " + value.ToString() + "."); } private void ConfirmPattern(Player player) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) PreviewSnapshot lastPreview = _lastPreview; if (lastPreview == null || lastPreview.IsReplant) { Message(player, (lastPreview != null) ? RunicText.Get("text_34619d7a206b") : RunicText.Get("text_a57d28e2b503")); Trace("pattern confirmation produced no mutation because no ordinary preview was ready."); } else { ExecuteBatch(player, lastPreview.Piece, lastPreview.CropId, lastPreview.Positions, lastPreview.Rotation); } } private void ConfirmReplant(Player player) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //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_0092: Unknown result type (might be due to invalid IL or missing references) Piece selectedPiece = player.GetSelectedPiece(); if (!IsPlantPiece(selectedPiece)) { Message(player, RunicText.Get("text_f8eb54e7f3df")); Trace("replant confirmation ignored because no crop is selected."); return; } string text = PrefabIdentity.Of(((Component)selectedPiece).gameObject); if (!_replant.TryConfirm(text, out var positions, out var reasonCode)) { Message(player, FriendlyReason(reasonCode)); Trace("replant confirmation denied: " + reasonCode + "."); return; } Quaternion rotation = Quaternion.Euler(0f, ((Component)play