Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of BotanistUseSoilPourers v1.0.3
BotanistUseSoilPourer.dll
Decompiled 10 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.Json; using System.Text.Json.Serialization; using BotanistUseSoilPourer; using HarmonyLib; using Il2CppFishNet; using Il2CppInterop.Runtime.InteropTypes; using Il2CppScheduleOne; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Employees; using Il2CppScheduleOne.EntityFramework; using Il2CppScheduleOne.Equipping; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.NPCs; using Il2CppScheduleOne.NPCs.Behaviour; using Il2CppScheduleOne.ObjectScripts; using Il2CppScheduleOne.ObjectScripts.Soil; using Il2CppScheduleOne.Tiles; using Il2CppScheduleOne.Trash; using Il2CppSystem.Collections.Generic; using MelonLoader; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(BotanistUseSoilPourerMod), "Botanist Use Soil Pourer", "1.0.3", "Fortis", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("BotanistUseSoilPourer")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+c6dfe370d264d8c1cc6af6dffcdc51e1d71a60f0")] [assembly: AssemblyProduct("BotanistUseSoilPourer")] [assembly: AssemblyTitle("BotanistUseSoilPourer")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 BotanistUseSoilPourer { public class BotanistUseSoilPourerMod : MelonMod { [HarmonyPatch(typeof(PotActionBehaviour), "StartAction")] public static class PotActionBehaviourStartActionPatch { [HarmonyPostfix] private static void Postfix(PotActionBehaviour __instance) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 if (__instance.AssignedPot != null && (int)__instance.CurrentActionType == 1 && !__instance.IsAtPot()) { SoilPourer potSoilPourer = GetPotSoilPourer(__instance.AssignedPot); if (potSoilPourer != null && !CheckPreventer.ContainsKey(__instance.AssignedPot)) { Log("(PotActionBehaviourStartActionPatch/Postfix) Adding pot to check preventer", LogLevel.Debug); CheckPreventer.Add(__instance.AssignedPot, potSoilPourer); } } } } [HarmonyPatch(typeof(PotActionBehaviour), "ActiveMinPass")] public static class PotActionBehviourActiveMinPassPatch { [HarmonyPrefix] private static bool Prefix(PotActionBehaviour __instance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 if ((int)__instance.CurrentActionType != 1) { return true; } if ((int)__instance.CurrentState == 0) { SoilPourer val = null; if (CheckPreventer.ContainsKey(__instance.AssignedPot)) { val = CheckPreventer[__instance.AssignedPot]; } if (val == null) { return true; } if (val.SoilID == string.Empty) { return true; } __instance.WalkToPot(); return false; } return true; } [HarmonyPostfix] private static void Postfix(PotActionBehaviour __instance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)__instance.CurrentActionType != 1) { return; } SoilPourer val = null; if (CheckPreventer.ContainsKey(__instance.AssignedPot)) { val = CheckPreventer[__instance.AssignedPot]; } if (val == null) { return; } if (val.SoilID == string.Empty) { if (__instance.IsAtPot()) { PourSoilIntoPourer(__instance, val); if (val.SoilID != string.Empty) { val.ActivateSound.Play(); DispenseSoilQuick(val.SoilID, __instance.AssignedPot); val.SendSoil(string.Empty); val.SetSoilLevel(0f); EndBotanistTask(__instance); } } } else if (__instance.IsAtPot()) { Log("(PotActionBehaviourActiveMinPassPatch/Postfix) Activating soil pourer", LogLevel.Debug); val.ActivateSound.Play(); DispenseSoilQuick(val.SoilID, __instance.AssignedPot); val.SendSoil(string.Empty); val.SetSoilLevel(0f); EndBotanistTask(__instance); } } } private enum LogLevel { Debug, Info, Warn, Error, Fatal } private static Configuration _config = null; private static readonly string ConfigDirectoryPath = Path.Combine(MelonEnvironment.UserDataDirectory, "BotanistUseSoilPourer"); private static readonly string ConfigPath = Path.Combine(ConfigDirectoryPath, "configuration.json"); private static Dictionary<Pot, SoilPourer> CheckPreventer = new Dictionary<Pot, SoilPourer>(); public override void OnInitializeMelon() { Log("Initializing...", LogLevel.Info); LoadConfigFromFile(); Log($"Enabled: {_config.enabled}", LogLevel.Info); if (_config.enabled) { if (_config.debug) { Log("Debug Mode Enabled", LogLevel.Debug); } Log("Initialized", LogLevel.Info); } } public override void OnDeinitializeMelon() { Log("(OnDeinitializeMelon) Mod unloaded", LogLevel.Info); } private static void DispenseSoilQuick(string id, Pot pot) { pot.SetSoilID(id); pot.SetSoilState((ESoilState)0); pot.AddSoil(pot.SoilCapacity); pot.SetSoilUses(Registry.GetItem<SoilDefinition>(id).Uses); if (InstanceFinder.IsServer) { pot.PushSoilDataToServer(); } } private static void EndBotanistTask(PotActionBehaviour behaviour) { if (CheckPreventer.ContainsKey(behaviour.AssignedPot)) { Log("(EndBotanistTask) Removing pot from check preventer", LogLevel.Debug); CheckPreventer.Remove(behaviour.AssignedPot); } behaviour.StopPerformAction(); behaviour.CompleteAction(); ((Behaviour)behaviour).End_Server(); ((Employee)behaviour.botanist).SetIdle(true); } private static void PourSoilIntoPourer(PotActionBehaviour behaviour, SoilPourer pourer) { //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) if (behaviour.AssignedPot == null) { Log("(PourSoilIntoPourer) PotActionBehaviour is null", LogLevel.Warn); return; } ItemInstance val = null; string[] soilIDS = GetSoilIDS(); for (int i = 0; i < soilIDS.Length; i++) { val = ((Behaviour)behaviour).Npc.Inventory.GetFirstItem(soilIDS[i], (ItemFilter)null); if (val != null) { break; } } if (val == null) { Log("(PourSoilIntoPourer) Botanist does not have soil", LogLevel.Warn); return; } ((Il2CppObjectBase)val.Definition).TryCast<SoilDefinition>(); SoilDefinition val2 = ((Il2CppObjectBase)val.Definition).TryCast<SoilDefinition>(); if (val2 == null) { Log("(PourSoilIntoPourer) SoilDefinition is null", LogLevel.Warn); return; } pourer.SendSoil(((ItemDefinition)val2).ID); Equippable_Soil val3 = ((Il2CppObjectBase)((ItemDefinition)val2).Equippable).TryCast<Equippable_Soil>(); if (val3 != null) { NetworkSingleton<TrashManager>.Instance.CreateTrashItem(((Equippable_Pourable)val3).PourablePrefab.TrashItem.ID, ((Component)behaviour).transform.position + Vector3.up * 0.5f, Random.rotation, default(Vector3), "", false); } val.ChangeQuantity(-1); } private static string[] GetSoilIDS() { return new string[3] { "soil", "longlifesoil", "extralonglifesoil" }; } private static SoilPourer? GetPotSoilPourer(Pot pot) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Expected O, but got Unknown //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_0448: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Expected O, but got Unknown Log("(GetSoilPourer) Fired", LogLevel.Debug); Coordinate val = new Coordinate(((GridItem)pot).OriginCoordinate); Log($"(GetPotSoilPourer) Assigned Pot Coords x: {val.x}, y: {val.y}", LogLevel.Debug); List<SoilPourer> list = new List<SoilPourer>(); for (int i = 1; i < 4; i++) { Coordinate val2 = new Coordinate(val.x + i, val.y); Coordinate val3 = new Coordinate(val.x - i, val.y); Coordinate val4 = new Coordinate(val.x, val.y + i); Coordinate val5 = new Coordinate(val.x, val.y - i); Tile tile = ((GridItem)pot).OwnerGrid.GetTile(val2); Tile tile2 = ((GridItem)pot).OwnerGrid.GetTile(val3); Tile tile3 = ((GridItem)pot).OwnerGrid.GetTile(val4); Tile tile4 = ((GridItem)pot).OwnerGrid.GetTile(val5); Tile[] array = (Tile[])(object)new Tile[4] { tile, tile2, tile3, tile4 }; for (int j = 0; j < array.Length; j++) { if (array[j] == null) { Log($"(GetPotSoilPourer) Tile at index {j} is null, skipping", LogLevel.Debug); continue; } Log($"(GetPotSoilPourer) Checking tile at x: {array[j].x}, y: {array[j].y}", LogLevel.Debug); if (!TryGetSoilPourer(array[j], out SoilPourer pourer)) { Log($"(GetPotSoilPourer) Tile at x: {array[j].x}, y: {array[j].y} contains no soil pourers", LogLevel.Debug); } else if (pourer == null) { Log($"(GetPotSoilPourer) Tile at x: {array[j].x}, y: {array[j].y} contains a soil pourer but soil pourer returned is null", LogLevel.Warn); } else { Log($"(GetPotSoilPourer) Soil Pourer found at x: {array[j].x}, y: {array[j].y}", LogLevel.Debug); list.Add(pourer); } } } SoilPourer result = null; if (list.Count <= 0) { return result; } Log($"(GetPotSoilPourer) pourersAroundPot Count: {list.Count}", LogLevel.Debug); for (int k = 0; k < list.Count; k++) { Coordinate val6 = new Coordinate(((GridItem)list[k]).OriginCoordinate); Log($"(GetPotSoilPourer) Checking if soil pourer at x: {val6.x}, y: {val6.y} pot is assigned pot", LogLevel.Debug); List<Pot> pots = list[k].GetPots(); Enumerator<Pot> enumerator = pots.GetEnumerator(); while (enumerator.MoveNext()) { Pot current = enumerator.Current; Coordinate val7 = new Coordinate(((GridItem)current).OriginCoordinate); Log($"(GetPotSoilPourer) Checking if pot at x: {val7.x}, y: {val7.y} matches assigned pot at x: {val7.x}, y: {val7.y}", LogLevel.Debug); if (val7.x == val.x && val7.y == val.y) { Log("(GetPotSoilPourer) Pot matched, returning soil pourer", LogLevel.Debug); result = list[k]; } } } return result; } private static bool TryGetSoilPourer(Tile tile, out SoilPourer? pourer) { pourer = null; Enumerator<GridItem> enumerator = tile.BuildableOccupants.GetEnumerator(); SoilPourer val = default(SoilPourer); while (enumerator.MoveNext()) { GridItem current = enumerator.Current; if (current == null || !((Component)current).TryGetComponent<SoilPourer>(ref val)) { continue; } pourer = val; break; } return Object.op_Implicit((Object)(object)pourer); } private static void LoadConfigFromFile() { if (!Directory.Exists(ConfigDirectoryPath)) { Directory.CreateDirectory(ConfigDirectoryPath); } if (!File.Exists(ConfigPath)) { CreateNewConfigFile(); return; } Configuration configuration = new Configuration { enabled = true, debug = false }; string json = File.ReadAllText(ConfigPath); Configuration configuration2 = JsonSerializer.Deserialize<Configuration>(json); if (configuration2 == null) { _config = configuration; return; } configuration.enabled = configuration2.enabled; configuration.debug = configuration2.debug; _config = configuration; } private static void CreateNewConfigFile() { Configuration configuration = new Configuration { enabled = true, debug = false }; JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions(); jsonSerializerOptions.WriteIndented = true; string contents = JsonSerializer.Serialize(configuration, jsonSerializerOptions); File.WriteAllText(ConfigPath, contents); _config = configuration; } private static void Log(string message, LogLevel level) { string logPrefix = GetLogPrefix(level); if (level != 0 || _config.debug) { MelonLogger.Msg(logPrefix + " " + message); } } private static string GetLogPrefix(LogLevel level) { return level switch { LogLevel.Debug => "[DEBUG]", LogLevel.Info => "[INFO]", LogLevel.Warn => "[WARN]", LogLevel.Error => "[ERROR]", LogLevel.Fatal => "[FATAL]", _ => "[MISC]", }; } } internal class Configuration { [JsonPropertyName("enabled")] public bool enabled { get; set; } [JsonPropertyName("debug")] public bool debug { get; set; } } }
BotanistUseSoilPourer_Mono.dll
Decompiled 10 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BotanistUseSoilPourer; using FishNet; using HarmonyLib; using MelonLoader; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using ScheduleOne; using ScheduleOne.DevUtilities; using ScheduleOne.Employees; using ScheduleOne.EntityFramework; using ScheduleOne.Equipping; using ScheduleOne.ItemFramework; using ScheduleOne.NPCs; using ScheduleOne.NPCs.Behaviour; using ScheduleOne.ObjectScripts; using ScheduleOne.ObjectScripts.Soil; using ScheduleOne.Tiles; using ScheduleOne.Trash; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(BotanistUseSoilPourerMod), "Botanist Use Soil Pourer", "1.0.3", "Fortis", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BotanistUseSoilPourer_Mono")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+c6dfe370d264d8c1cc6af6dffcdc51e1d71a60f0")] [assembly: AssemblyProduct("BotanistUseSoilPourer_Mono")] [assembly: AssemblyTitle("BotanistUseSoilPourer_Mono")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 BotanistUseSoilPourer { public class BotanistUseSoilPourerMod : MelonMod { [HarmonyPatch(typeof(PotActionBehaviour), "StartAction")] public static class PotActionBehaviourStartActionPatch { [HarmonyPostfix] private static void Postfix(PotActionBehaviour __instance) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 if ((object)IsAtPot != null) { if (__instance.AssignedPot != null && (int)__instance.CurrentActionType == 1 && !(bool)IsAtPot.Invoke(__instance, null)) { SoilPourer potSoilPourer = GetPotSoilPourer(__instance.AssignedPot); if (potSoilPourer != null && !CheckPreventer.ContainsKey(__instance.AssignedPot)) { Log("(PotActionBehaviourStartActionPatch/Postfix) Adding pot to check preventer", LogLevel.Debug); CheckPreventer.Add(__instance.AssignedPot, potSoilPourer); } } } else { Log("(PotActionBehaviourStartActionPatch/Postfix) IsAtPot is null", LogLevel.Warn); } } } [HarmonyPatch(typeof(PotActionBehaviour), "ActiveMinPass")] public static class PotActionBehviourActiveMinPassPatch { [HarmonyPrefix] private static bool Prefix(PotActionBehaviour __instance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 if ((int)__instance.CurrentActionType != 1) { return true; } if ((int)__instance.CurrentState == 0) { SoilPourer val = null; if (CheckPreventer.ContainsKey(__instance.AssignedPot)) { val = CheckPreventer[__instance.AssignedPot]; } if (val == null) { return true; } if (val.SoilID == string.Empty) { return true; } __instance.WalkToPot(); return false; } return true; } [HarmonyPostfix] private static void Postfix(PotActionBehaviour __instance) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 if ((object)IsAtPot != null) { if ((int)__instance.CurrentActionType != 1) { return; } SoilPourer val = null; if (CheckPreventer.ContainsKey(__instance.AssignedPot)) { val = CheckPreventer[__instance.AssignedPot]; } if (val == null) { return; } if (val.SoilID == string.Empty) { if ((bool)IsAtPot.Invoke(__instance, null)) { PourSoilIntoPourer(__instance, val); if (val.SoilID != string.Empty) { val.ActivateSound.Play(); DispenseSoilQuick(val.SoilID, __instance.AssignedPot); val.SendSoil(string.Empty); val.SetSoilLevel(0f); EndBotanistTask(__instance); } } } else if ((bool)IsAtPot.Invoke(__instance, null)) { Log("(PotActionBehaviourActiveMinPassPatch/Postfix) Activating soil pourer", LogLevel.Debug); val.ActivateSound.Play(); DispenseSoilQuick(val.SoilID, __instance.AssignedPot); val.SendSoil(string.Empty); val.SetSoilLevel(0f); EndBotanistTask(__instance); } } else { Log("(PotActionBehaviourActiveMinPassPatch/Postfix) IsAtPot is null", LogLevel.Warn); } } } private enum LogLevel { Debug, Info, Warn, Error, Fatal } private static Configuration _config = null; private static readonly string ConfigDirectoryPath = Path.Combine(MelonEnvironment.UserDataDirectory, "BotanistUseSoilPourer"); private static readonly string ConfigPath = Path.Combine(ConfigDirectoryPath, "configuration.json"); private static Dictionary<Pot, SoilPourer> CheckPreventer = new Dictionary<Pot, SoilPourer>(); private static MethodInfo IsAtPot = typeof(PotActionBehaviour).GetMethod("IsAtPot", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); private static MethodInfo StopPerformAction = typeof(PotActionBehaviour).GetMethod("StopPerformAction", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); private static MethodInfo CompleteAction = typeof(PotActionBehaviour).GetMethod("CompleteAction", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); private static MethodInfo GetPots = typeof(SoilPourer).GetMethod("GetPots", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); public override void OnInitializeMelon() { Log("Initializing...", LogLevel.Info); LoadConfigFromFile(); Log($"Enabled: {_config.enabled}", LogLevel.Info); if (_config.enabled) { if (_config.debug) { Log("Debug Mode Enabled", LogLevel.Debug); } Log("Initialized", LogLevel.Info); } } public override void OnDeinitializeMelon() { Log("(OnDeinitializeMelon) Mod unloaded", LogLevel.Info); } private static void DispenseSoilQuick(string id, Pot pot) { pot.SetSoilID(id); pot.SetSoilState((ESoilState)0); pot.AddSoil(pot.SoilCapacity); pot.SetSoilUses(Registry.GetItem<SoilDefinition>(id).Uses); if (InstanceFinder.IsServer) { pot.PushSoilDataToServer(); } } private static void EndBotanistTask(PotActionBehaviour behaviour) { if ((object)StopPerformAction != null && (object)CompleteAction != null) { if (CheckPreventer.ContainsKey(behaviour.AssignedPot)) { Log("(EndBotanistTask) Removing pot from check preventer", LogLevel.Debug); CheckPreventer.Remove(behaviour.AssignedPot); } StopPerformAction.Invoke(behaviour, null); CompleteAction.Invoke(behaviour, null); ((Behaviour)behaviour).End_Server(); NPC npc = ((Behaviour)behaviour).Npc; Botanist val = (Botanist)(object)((npc is Botanist) ? npc : null); if (val != null) { ((Employee)val).SetIdle(true); } else { Log("(EndBotanistTask) Botanist is null", LogLevel.Warn); } } else { Log($"(EndBotanistTask) StopPeformAction is null: {(object)StopPerformAction == null}, CompleteAction is null: {(object)CompleteAction == null}", LogLevel.Debug); } } private static void PourSoilIntoPourer(PotActionBehaviour behaviour, SoilPourer pourer) { //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) if (behaviour.AssignedPot == null) { Log("(PourSoilIntoPourer) PotActionBehaviour is null", LogLevel.Warn); return; } ItemInstance val = null; string[] soilIDS = GetSoilIDS(); for (int i = 0; i < soilIDS.Length; i++) { val = ((Behaviour)behaviour).Npc.Inventory.GetFirstItem(soilIDS[i], (ItemFilter)null); if (val != null) { break; } } if (val == null) { Log("(PourSoilIntoPourer) Botanist does not have soil", LogLevel.Warn); return; } ItemDefinition definition = val.Definition; SoilDefinition val2 = (SoilDefinition)(object)((definition is SoilDefinition) ? definition : null); if (val2 == null) { Log("(PourSoilIntoPourer) SoilDefinition is null", LogLevel.Warn); return; } pourer.SendSoil(((ItemDefinition)val2).ID); ? val3 = NetworkSingleton<TrashManager>.Instance; Equippable equippable = ((ItemDefinition)val2).Equippable; ((TrashManager)val3).CreateTrashItem(((Equippable_Pourable)((equippable is Equippable_Soil) ? equippable : null)).PourablePrefab.TrashItem.ID, ((Component)behaviour).transform.position + Vector3.up * 0.5f, Random.rotation, default(Vector3), "", false); val.ChangeQuantity(-1); } private static string[] GetSoilIDS() { return new string[3] { "soil", "longlifesoil", "extralonglifesoil" }; } private static SoilPourer? GetPotSoilPourer(Pot pot) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Expected O, but got Unknown //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Expected O, but got Unknown Log("(GetSoilPourer) Fired", LogLevel.Debug); if ((object)GetPots == null) { Log("(GetSoilPourer) GetPots Reflection method is null", LogLevel.Error); return null; } Coordinate val = new Coordinate(((GridItem)pot).OriginCoordinate); Log($"(GetPotSoilPourer) Assigned Pot Coords x: {val.x}, y: {val.y}", LogLevel.Debug); List<SoilPourer> list = new List<SoilPourer>(); for (int i = 1; i < 4; i++) { Coordinate val2 = new Coordinate(val.x + i, val.y); Coordinate val3 = new Coordinate(val.x - i, val.y); Coordinate val4 = new Coordinate(val.x, val.y + i); Coordinate val5 = new Coordinate(val.x, val.y - i); Tile tile = ((GridItem)pot).OwnerGrid.GetTile(val2); Tile tile2 = ((GridItem)pot).OwnerGrid.GetTile(val3); Tile tile3 = ((GridItem)pot).OwnerGrid.GetTile(val4); Tile tile4 = ((GridItem)pot).OwnerGrid.GetTile(val5); Tile[] array = (Tile[])(object)new Tile[4] { tile, tile2, tile3, tile4 }; for (int j = 0; j < array.Length; j++) { if (array[j] == null) { Log($"(GetPotSoilPourer) Tile at index {j} is null, skipping", LogLevel.Debug); continue; } Log($"(GetPotSoilPourer) Checking tile at x: {array[j].x}, y: {array[j].y}", LogLevel.Debug); if (!TryGetSoilPourer(array[j], out SoilPourer pourer)) { Log($"(GetPotSoilPourer) Tile at x: {array[j].x}, y: {array[j].y} contains no soil pourers", LogLevel.Debug); continue; } if (pourer == null) { Log($"(GetPotSoilPourer) Tile at x: {array[j].x}, y: {array[j].y} contains a soil pourer but soil pourer returned is null", LogLevel.Warn); continue; } Log($"(GetPotSoilPourer) Soil Pourer found at x: {array[j].x}, y: {array[j].y}", LogLevel.Debug); list.Add(pourer); } } SoilPourer result = null; if (list.Count <= 0) { return result; } Log($"(GetPotSoilPourer) pourersAroundPot Count: {list.Count}", LogLevel.Debug); for (int k = 0; k < list.Count; k++) { Coordinate val6 = new Coordinate(((GridItem)list[k]).OriginCoordinate); Log($"(GetPotSoilPourer) Checking if soil pourer at x: {val6.x}, y: {val6.y} pot is assigned pot", LogLevel.Debug); object obj = GetPots.Invoke(list[k], null); if (obj == null) { Log("(GetPotSoilPourer) pourerPots is null", LogLevel.Error); continue; } if (!(obj is List<Pot> list2)) { Log("(GetPotSoilPourer) pourerPots is not a List<Pot> cannot execute", LogLevel.Error); continue; } if (list2 == null) { Log("(GetPotSoilPourer) potsAroundPourer is null cannot execute", LogLevel.Error); continue; } if (list2.Count <= 0) { Log("(GetPotSoilPourer) potsAroundPourer count is 0", LogLevel.Debug); continue; } foreach (Pot item in list2) { if (item == null) { Log("(GetPotSoilPourer) pourerPot is null", LogLevel.Debug); continue; } Coordinate val7 = new Coordinate(((GridItem)item).OriginCoordinate); Log($"(GetPotSoilPourer) Checking if pot at x: {val7.x}, y: {val7.y} matches assigned pot at x: {val.x}, y: {val.y}", LogLevel.Debug); if (val7.x == val.x && val7.y == val.y) { Log("(GetPotSoilPourer) Pot matched, returning soil pourer", LogLevel.Debug); result = list[k]; } } } return result; } private static bool TryGetSoilPourer(Tile tile, out SoilPourer? pourer) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown pourer = null; foreach (GridItem buildableOccupant in tile.BuildableOccupants) { if (buildableOccupant == null || !(buildableOccupant is SoilPourer)) { continue; } pourer = (SoilPourer)buildableOccupant; break; } return Object.op_Implicit((Object)(object)pourer); } private static void LoadConfigFromFile() { if (!Directory.Exists(ConfigDirectoryPath)) { Directory.CreateDirectory(ConfigDirectoryPath); } if (!File.Exists(ConfigPath)) { CreateNewConfigFile(); return; } Configuration configuration = new Configuration { enabled = true, debug = false }; string text = File.ReadAllText(ConfigPath); Configuration configuration2 = JsonConvert.DeserializeObject<Configuration>(text); if (configuration2 == null) { _config = configuration; return; } configuration.enabled = configuration2.enabled; configuration.debug = configuration2.debug; _config = configuration; } private static void CreateNewConfigFile() { Configuration configuration = new Configuration { enabled = true, debug = false }; string contents = JsonConvert.SerializeObject((object)configuration, (Formatting)1); File.WriteAllText(ConfigPath, contents); _config = configuration; } private static void Log(string message, LogLevel level) { string logPrefix = GetLogPrefix(level); if (level != 0 || _config.debug) { MelonLogger.Msg(logPrefix + " " + message); } } private static string GetLogPrefix(LogLevel level) { return level switch { LogLevel.Debug => "[DEBUG]", LogLevel.Info => "[INFO]", LogLevel.Warn => "[WARN]", LogLevel.Error => "[ERROR]", LogLevel.Fatal => "[FATAL]", _ => "[MISC]", }; } } internal class Configuration { [JsonProperty("enabled")] public bool enabled { get; set; } [JsonProperty("debug")] public bool debug { get; set; } } }