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.1
BotanistUseSoilPourer_Mono.dll
Decompiled 3 weeks 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.1", "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")] [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); 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).SendEnd(); 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_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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_0275: 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_0281: Expected O, but got Unknown //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Expected O, but got Unknown //IL_02db: Expected O, but got Unknown //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Expected O, but got Unknown //IL_030e: Expected O, but got Unknown //IL_043c: Unknown result type (might be due to invalid IL or missing references) //IL_0441: Unknown result type (might be due to invalid IL or missing references) //IL_0448: Expected O, but got Unknown Log("(GetSoilPourer) Fired", LogLevel.Debug); Coordinate val = new Coordinate(((GridItem)pot).OriginCoordinate); Log($"(GetPotSoilPourers) 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($"(GetPotSoilPourers) Checking tile at x: {array[j].x}, y: {array[j].y}", LogLevel.Debug); if (!TryGetSoilPourer(array[j], out SoilPourer pourer)) { Log($"(GetPotSoilPourers) Tile at x: {array[j].x}, y: {array[j].y} contains no soil pourers", LogLevel.Debug); continue; } if (pourer == null) { Log($"(GetPotSoilPourers) Tile at x: {array[j].x}, y: {array[j].y} contains a soil pourer but soil pourer returned is null", LogLevel.Warn); continue; } Log($"(GetPotSoilPourers) Soil Pourer found at x: {array[j].x}, y: {array[j].y}", LogLevel.Debug); list.Add(pourer); } } } SoilPourer val6 = null; if (list.Count <= 0) { return val6; } Log($"(GetPotSoilPourers) pourersAroundPot Count: {list.Count}", LogLevel.Debug); for (int k = 0; k < list.Count; k++) { Coordinate val7 = new Coordinate(((GridItem)list[k]).OriginCoordinate); Log($"(GetPotSoilPourers) Checking if soil pourer at x: {val7.x}, y: {val7.y} pot is assigned pot", LogLevel.Debug); Coordinate val8 = new Coordinate(((GridItem)list[k]).OriginCoordinate) + Coordinate.RotateCoordinates(new Coordinate(0, 1), (float)((GridItem)list[k]).Rotation); Coordinate val9 = new Coordinate(((GridItem)list[k]).OriginCoordinate) + Coordinate.RotateCoordinates(new Coordinate(1, 1), (float)((GridItem)list[k]).Rotation); Tile tile5 = ((GridItem)list[k]).OwnerGrid.GetTile(val8); Tile tile6 = ((GridItem)list[k]).OwnerGrid.GetTile(val9); List<Pot> list2 = new List<Pot>(); if ((Object)(object)tile5 != (Object)null && (Object)(object)tile6 != (Object)null) { Pot val10 = null; foreach (GridItem buildableOccupant in tile5.BuildableOccupants) { if (buildableOccupant is Pot) { val10 = (Pot)(object)((buildableOccupant is Pot) ? buildableOccupant : null); break; } } if ((Object)(object)val10 != (Object)null && tile6.BuildableOccupants.Contains((GridItem)(object)val10)) { list2.Add(val10); } } if (list2.Count <= 0) { Log("(GetPotSoilPourers) Tile pots count is 0 or less", LogLevel.Debug); return val6; } Log($"(GetPotSoilPourers) Soil pourer pots count: {list2.Count}", LogLevel.Debug); for (int l = 0; l < list2.Count; l++) { Coordinate val11 = new Coordinate(((GridItem)list2[l]).OriginCoordinate); Log($"(GetPotSoilPourers) Checking soil pourer pot at x: {val11.x}, y: {val11.y} matches assigned pot at x: {val.x}, y {val.y}", LogLevel.Debug); if (val11.x == val.x && val11.y == val.y) { Log("(GetPotSoilPourers) Adding Soil pourer", LogLevel.Debug); val6 = list[k]; break; } } } Log($"(GetPotSoilPourers) Soil pourer to be activated is null: {val6 == null}", LogLevel.Debug); return val6; } 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; } } }
BotanistUseSoilPourer.dll
Decompiled 3 weeks 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.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(BotanistUseSoilPourerMod), "Botanist Use Soil Pourer", "1.0.1", "Fortis", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("BotanistUseSoilPourer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [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_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_000c: Unknown result type (might be due to invalid IL or missing references) 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_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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).SendEnd(); ((Employee)behaviour.botanist).SetIdle(true); } private static void PourSoilIntoPourer(PotActionBehaviour behaviour, SoilPourer pourer) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Expected O, but got Unknown //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Expected O, but got Unknown //IL_03e7: Expected O, but got Unknown //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Unknown result type (might be due to invalid IL or missing references) //IL_0415: Expected O, but got Unknown //IL_041a: Expected O, but got Unknown //IL_0511: Unknown result type (might be due to invalid IL or missing references) //IL_0516: Unknown result type (might be due to invalid IL or missing references) //IL_051d: Expected O, but got Unknown Log("(GetSoilPourer) Fired", LogLevel.Debug); Coordinate val = new Coordinate(((GridItem)pot).OriginCoordinate); Log($"(GetPotSoilPourers) 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($"(GetPotSoilPourers) Tile at index {j} is null, skipping", LogLevel.Debug); continue; } Log($"(GetPotSoilPourers) Checking tile at x: {array[j].x}, y: {array[j].y}", LogLevel.Debug); if (!TryGetSoilPourer(array[j], out SoilPourer pourer)) { Log($"(GetPotSoilPourers) Tile at x: {array[j].x}, y: {array[j].y} contains no soil pourers", LogLevel.Debug); } else if (pourer == null) { Log($"(GetPotSoilPourers) Tile at x: {array[j].x}, y: {array[j].y} contains a soil pourer but soil pourer returned is null", LogLevel.Warn); } else { Log($"(GetPotSoilPourers) Soil Pourer found at x: {array[j].x}, y: {array[j].y}", LogLevel.Debug); list.Add(pourer); } } } SoilPourer val6 = null; if (list.Count <= 0) { return val6; } Log($"(GetPotSoilPourers) pourersAroundPot Count: {list.Count}", LogLevel.Debug); Pot val11 = default(Pot); for (int k = 0; k < list.Count; k++) { Coordinate val7 = new Coordinate(((GridItem)list[k]).OriginCoordinate); Log($"(GetPotSoilPourers) Checking if soil pourer at x: {val7.x}, y: {val7.y} pot is assigned pot", LogLevel.Debug); Coordinate val8 = new Coordinate(((GridItem)list[k]).OriginCoordinate) + Coordinate.RotateCoordinates(new Coordinate(0, 1), (float)((GridItem)list[k]).Rotation); Coordinate val9 = new Coordinate(((GridItem)list[k]).OriginCoordinate) + Coordinate.RotateCoordinates(new Coordinate(1, 1), (float)((GridItem)list[k]).Rotation); Tile tile5 = ((GridItem)list[k]).OwnerGrid.GetTile(val8); Tile tile6 = ((GridItem)list[k]).OwnerGrid.GetTile(val9); List<Pot> list2 = new List<Pot>(); if ((Object)(object)tile5 != (Object)null && (Object)(object)tile6 != (Object)null) { Pot val10 = null; Enumerator<GridItem> enumerator = tile5.BuildableOccupants.GetEnumerator(); while (enumerator.MoveNext()) { if (((Component)enumerator.Current).TryGetComponent<Pot>(ref val11)) { val10 = val11; break; } } if ((Object)(object)val10 != (Object)null && tile6.BuildableOccupants.Contains((GridItem)(object)val10)) { list2.Add(val10); } } if (list2.Count <= 0) { Log("(GetPotSoilPourers) Tile pots count is 0 or less", LogLevel.Debug); return val6; } Log($"(GetPotSoilPourers) Soil pourer pots count: {list2.Count}", LogLevel.Debug); for (int l = 0; l < list2.Count; l++) { Coordinate val12 = new Coordinate(((GridItem)list2[l]).OriginCoordinate); Log($"(GetPotSoilPourers) Checking soil pourer pot at x: {val12.x}, y: {val12.y} matches assigned pot at x: {val.x}, y {val.y}", LogLevel.Debug); if (val12.x == val.x && val12.y == val.y) { Log("(GetPotSoilPourers) Adding Soil pourer", LogLevel.Debug); val6 = list[k]; break; } } } Log($"(GetPotSoilPourers) Soil pourer to be activated is null: {val6 == null}", LogLevel.Debug); return val6; } 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)) { 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 }; Configuration configuration2 = JsonSerializer.Deserialize<Configuration>(File.ReadAllText(ConfigPath)); if (configuration2 == null) { _config = configuration; return; } configuration.enabled = configuration2.enabled; configuration.debug = configuration2.debug; _config = configuration; } private static void CreateNewConfigFile() { Configuration obj = new Configuration { enabled = true, debug = false }; File.WriteAllText(contents: JsonSerializer.Serialize(obj, new JsonSerializerOptions { WriteIndented = true }), path: ConfigPath); _config = obj; } 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; } } }