Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of SuperGrow v1.3.4
SuperGrow_Il2Cpp.dll
Decompiled 15 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne; using Il2CppScheduleOne.Core.Items.Framework; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Equipping; using Il2CppScheduleOne.Growing; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.ObjectScripts; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.PlayerTasks; using Il2CppScheduleOne.PlayerTasks.Tasks; using Il2CppScheduleOne.StationFramework; using Il2CppScheduleOne.Storage; using Il2CppScheduleOne.Trash; using Il2CppScheduleOne.UI.Stations; using Il2CppSystem.Collections.Generic; using Il2CppTMPro; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using SuperGrow; using SuperGrow.Features; using SuperGrow.Patches; using SuperGrow.Utils; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Core), "SuperGrow", "1.3.4", "HazDS", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("SuperGrow_Il2Cpp")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+22bbaa0cd7f8c88418ee8cc3f9785971198326d8")] [assembly: AssemblyProduct("SuperGrow_Il2Cpp")] [assembly: AssemblyTitle("SuperGrow_Il2Cpp")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.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] [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] [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 SuperGrow { internal static class SuperGrowSettings { private static bool _initialized; private static MelonPreferences_Category? _prefsCategory; public static MelonPreferences_Entry<int> PgrRequired { get; private set; } public static MelonPreferences_Entry<int> SpeedGrowRequired { get; private set; } public static MelonPreferences_Entry<int> FertilizerRequired { get; private set; } public static MelonPreferences_Entry<int> OutputQuantity { get; private set; } public static MelonPreferences_Entry<int> CookTimeMinutes { get; private set; } public static MelonPreferences_Entry<float> YieldMultiplier { get; private set; } public static MelonPreferences_Entry<float> InstantGrowth { get; private set; } public static MelonPreferences_Entry<float> QualityChange { get; private set; } public static void Initialize() { if (!_initialized) { _prefsCategory = MelonPreferences.CreateCategory("SuperGrow", "SuperGrow Settings"); PgrRequired = _prefsCategory.CreateEntry<int>("PgrRequired", 1, "PGR Required", "Amount of PGR needed per craft", false, false, (ValueValidator)null, (string)null); SpeedGrowRequired = _prefsCategory.CreateEntry<int>("SpeedGrowRequired", 1, "Speed Grow Required", "Amount of Speed Grow needed per craft", false, false, (ValueValidator)null, (string)null); FertilizerRequired = _prefsCategory.CreateEntry<int>("FertilizerRequired", 1, "Fertilizer Required", "Amount of Fertilizer needed per craft", false, false, (ValueValidator)null, (string)null); OutputQuantity = _prefsCategory.CreateEntry<int>("OutputQuantity", 3, "Output Quantity", "Amount of SuperGrow produced per craft", false, false, (ValueValidator)null, (string)null); CookTimeMinutes = _prefsCategory.CreateEntry<int>("CookTimeMinutes", 30, "Cook Time (Minutes)", "Chemistry Station cook time in in-game minutes", false, false, (ValueValidator)null, (string)null); YieldMultiplier = _prefsCategory.CreateEntry<float>("YieldMultiplier", 1.5f, "Yield Multiplier", "Yield multiplier applied to plants (1.5 = 50% more yield)", false, false, (ValueValidator)null, (string)null); InstantGrowth = _prefsCategory.CreateEntry<float>("InstantGrowth", 0.5f, "Instant Growth", "Instant growth progress (0.5 = 50% instant growth)", false, false, (ValueValidator)null, (string)null); QualityChange = _prefsCategory.CreateEntry<float>("QualityChange", 1f, "Quality Change", "Quality modifier applied to plants", false, false, (ValueValidator)null, (string)null); Clamp(PgrRequired, 1, 10); Clamp(SpeedGrowRequired, 1, 10); Clamp(FertilizerRequired, 1, 10); Clamp(OutputQuantity, 1, 10); Clamp(CookTimeMinutes, 1, 240); Clamp(YieldMultiplier, 0.1f, 10f); Clamp(InstantGrowth, 0f, 1f); Clamp(QualityChange, -1f, 1f); _initialized = true; } } private static void Clamp(MelonPreferences_Entry<int> entry, int min, int max) { if (entry.Value < min) { entry.Value = min; } if (entry.Value > max) { entry.Value = max; } } private static void Clamp(MelonPreferences_Entry<float> entry, float min, float max) { if (entry.Value < min) { entry.Value = min; } if (entry.Value > max) { entry.Value = max; } } } public class Core : MelonMod { private bool _itemsInitialized; private int _nextInitAttemptTick; private const int InitAttemptIntervalMs = 250; public static Core Instance { get; private set; } public override void OnInitializeMelon() { Instance = this; SuperGrowSettings.Initialize(); MelonLogger.Msg("[SuperGrow v1.3.4] Initialized."); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (sceneName == "Menu") { _itemsInitialized = false; _nextInitAttemptTick = 0; ChemistryStationPatches.Reset(); } } public override void OnUpdate() { ChemistryStationPatches.DumpStationItemInitializePatchesOnce("OnUpdate"); if (_itemsInitialized && (Object)(object)Registry.GetItem("supergrow") != (Object)null) { return; } if ((Object)(object)Registry.GetItem("supergrow") != (Object)null) { ChemistryStationPatches.EnsureAdditiveStationItemPrefabs(); _itemsInitialized = true; } else if (ShouldAttemptInitNow()) { _itemsInitialized = false; if (SuperGrowWorldState.IsRegistryReady()) { SuperGrowCreator.CreateSuperGrowItem(); ChemistryStationPatches.EnsureAdditiveStationItemPrefabs(); _itemsInitialized = (Object)(object)Registry.GetItem("supergrow") != (Object)null; } } } private bool ShouldAttemptInitNow() { int tickCount = Environment.TickCount; if (tickCount - _nextInitAttemptTick < 0) { return false; } _nextInitAttemptTick = tickCount + 250; return true; } } internal static class SuperGrowAssets { private const string IconResourceName = "SuperGrow.Assets.SuperGrow_Icon.png"; private const string LabelResourceName = "SuperGrow.Assets.SuperGrow_Label.png"; private static Sprite? _icon; private static Texture2D? _labelTexture; private static bool _loggedIconLoadException; private static bool _loggedLabelLoadException; private static bool _loggedImageLoadException; public static Sprite? GetIconSprite() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_icon != (Object)null) { return _icon; } try { byte[] array = LoadEmbeddedResourceBytes("SuperGrow.Assets.SuperGrow_Icon.png"); if (array == null) { return null; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!TryLoadImage(val, array)) { MelonLogger.Warning("Failed to decode SuperGrow.Assets.SuperGrow_Icon.png"); return null; } ((Object)val).name = "SuperGrow_Icon"; _icon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); return _icon; } catch (Exception ex) { if (!_loggedIconLoadException) { _loggedIconLoadException = true; MelonLogger.Warning("Failed to load icon: " + ex.Message); MelonLogger.Warning(ex.StackTrace ?? "<no stack trace>"); } return null; } } public static Texture2D? GetLabelTexture() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown if ((Object)(object)_labelTexture != (Object)null) { return _labelTexture; } try { byte[] array = LoadEmbeddedResourceBytes("SuperGrow.Assets.SuperGrow_Label.png"); if (array == null) { return null; } _labelTexture = new Texture2D(2, 2, (TextureFormat)4, false); if (!TryLoadImage(_labelTexture, array)) { MelonLogger.Warning("Failed to decode SuperGrow.Assets.SuperGrow_Label.png"); _labelTexture = null; return null; } ((Object)_labelTexture).name = "SuperGrow_Label"; return _labelTexture; } catch (Exception ex) { if (!_loggedLabelLoadException) { _loggedLabelLoadException = true; MelonLogger.Error("Failed to load SuperGrow label texture: " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } _labelTexture = null; return null; } } private static byte[]? LoadEmbeddedResourceBytes(string resourceName) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); using Stream stream = executingAssembly.GetManifestResourceStream(resourceName); if (stream == null) { MelonLogger.Warning("Could not find embedded resource: " + resourceName); return null; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); return memoryStream.ToArray(); } private static bool TryLoadImage(Texture2D texture, byte[] bytes) { try { Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule") ?? typeof(Texture2D).Assembly.GetType("UnityEngine.ImageConversion"); if (type == null) { return false; } MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public); MethodInfo[] array = methods; bool flag = default(bool); foreach (MethodInfo methodInfo in array) { if (methodInfo.Name != "LoadImage") { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if ((parameters.Length != 2 && parameters.Length != 3) || parameters[0].ParameterType != typeof(Texture2D)) { continue; } Type parameterType = parameters[1].ParameterType; object obj; if (parameterType == typeof(byte[])) { obj = bytes; } else { if (!parameterType.IsGenericType || !(parameterType.GetGenericTypeDefinition() == typeof(Il2CppStructArray<>))) { continue; } Il2CppStructArray<byte> val = new Il2CppStructArray<byte>((long)bytes.Length); for (int j = 0; j < bytes.Length; j++) { ((Il2CppArrayBase<byte>)(object)val)[j] = bytes[j]; } obj = val; } object obj2 = ((parameters.Length != 3) ? methodInfo.Invoke(null, new object[2] { texture, obj }) : methodInfo.Invoke(null, new object[3] { texture, obj, false })); int num; if (obj2 is bool) { flag = (bool)obj2; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } return false; } catch (Exception ex) { if (!_loggedImageLoadException) { _loggedImageLoadException = true; MelonLogger.Warning("Failed to decode embedded image bytes via ImageConversion.LoadImage: " + ex.Message); MelonLogger.Warning(ex.StackTrace ?? "<no stack trace>"); } return false; } } } internal static class SuperGrowWorldState { private static bool _loggedReady; private static bool _ready; private static bool _loggedRegistryReadyException; public static bool IsRegistryReady() { try { if (_ready) { return true; } ItemDefinition item = Registry.GetItem("pgr"); AdditiveDefinition val = ((item != null) ? ((Il2CppObjectBase)item).TryCast<AdditiveDefinition>() : null); ItemDefinition item2 = Registry.GetItem("speedgrow"); AdditiveDefinition val2 = ((item2 != null) ? ((Il2CppObjectBase)item2).TryCast<AdditiveDefinition>() : null); ItemDefinition item3 = Registry.GetItem("fertilizer"); AdditiveDefinition val3 = ((item3 != null) ? ((Il2CppObjectBase)item3).TryCast<AdditiveDefinition>() : null); if ((Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null && (Object)(object)val3 == (Object)null) { return false; } _ready = true; if (!_loggedReady) { _loggedReady = true; MelonLogger.Msg("Registry appears ready; initializing item."); } return true; } catch (Exception ex) { if (!_loggedRegistryReadyException) { _loggedRegistryReadyException = true; MelonLogger.Warning("Registry readiness check failed: " + ex.Message); MelonLogger.Warning(ex.StackTrace ?? "<no stack trace>"); } return false; } } } } namespace SuperGrow.Utils { public static class Constants { public static class Game { public const string GAME_STUDIO = "TVGS"; public const string GAME_NAME = "Schedule I"; } public static class Additives { public const string PGR = "pgr"; public const string SPEED_GROW = "speedgrow"; public const string FERTILIZER = "fertilizer"; } public static class ItemIds { public const string SUPER_GROW = "supergrow"; } public static class DefaultEffects { public const float YIELD_MULTIPLIER = 1.5f; public const float INSTANT_GROWTH = 0.5f; public const float QUALITY_CHANGE = 1f; } public const string MOD_NAME = "SuperGrow"; public const string MOD_VERSION = "1.3.4"; public const string MOD_AUTHOR = "HazDS"; public const string PREFERENCES_CATEGORY = "SuperGrow"; } internal static class SuperGrowVisuals { internal static readonly Color PourColor = new Color(0.4f, 0.2f, 0.6f, 1f); internal static readonly Color LidTint = new Color(0.6f, 0.4f, 0.8f, 1f); internal static void ApplySuperGrowMaterialsToRenderers(Renderer[]? renderers) { //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) if (renderers == null) { return; } Texture2D labelTexture = SuperGrowAssets.GetLabelTexture(); if ((Object)(object)labelTexture == (Object)null) { MelonLogger.Warning("SuperGrow label texture is null, cannot apply"); return; } try { foreach (Renderer val in renderers) { if ((Object)(object)val == (Object)null) { continue; } string text = ((Object)val).name.ToLowerInvariant(); bool flag = text.Contains("label"); if (!flag) { foreach (Material item in (Il2CppArrayBase<Material>)(object)val.sharedMaterials) { if ((Object)(object)item != (Object)null && ((Object)item).name.ToLowerInvariant().Contains("label")) { flag = true; break; } } } bool flag2 = text.Contains("lid"); if (!flag2) { foreach (Material item2 in (Il2CppArrayBase<Material>)(object)val.sharedMaterials) { if ((Object)(object)item2 != (Object)null && ((Object)item2).name.ToLowerInvariant().Contains("lid")) { flag2 = true; break; } } } if (flag) { Il2CppReferenceArray<Material> materials = val.materials; for (int j = 0; j < ((Il2CppArrayBase<Material>)(object)materials).Length; j++) { Material val2 = ((Il2CppArrayBase<Material>)(object)materials)[j]; if (!((Object)(object)val2 == (Object)null)) { val2.mainTexture = (Texture)(object)labelTexture; if (val2.HasProperty("_BaseMap")) { val2.SetTexture("_BaseMap", (Texture)(object)labelTexture); } if (val2.HasProperty("_MainTex")) { val2.SetTexture("_MainTex", (Texture)(object)labelTexture); } } } val.materials = materials; } else { if (!flag2) { continue; } Il2CppReferenceArray<Material> materials2 = val.materials; for (int k = 0; k < ((Il2CppArrayBase<Material>)(object)materials2).Length; k++) { Material val3 = ((Il2CppArrayBase<Material>)(object)materials2)[k]; if (!((Object)(object)val3 == (Object)null)) { val3.color = LidTint; if (val3.HasProperty("_BaseColor")) { val3.SetColor("_BaseColor", LidTint); } if (val3.HasProperty("_Color")) { val3.SetColor("_Color", LidTint); } } } val.materials = materials2; } } } catch (Exception ex) { MelonLogger.Error("Failed to apply SuperGrow materials: " + ex.Message); MelonLogger.Error(ex.StackTrace); } } } } namespace SuperGrow.Patches { [HarmonyPatch] internal static class ChemistryStationPatches { private readonly struct PendingTrashReskin { public string TrashId { get; } public string AdditiveId { get; } public PendingTrashReskin(string trashId, string additiveId) { TrashId = trashId; AdditiveId = additiveId; } } private static StationRecipe? _superGrowRecipe; private static bool _additivesPatched; private static bool _loggedMissingStationItemTemplate; private static bool _loggedRegistryStart; private static bool _loggedRecipeNotReady; private static int _superGrowBeginAuditUntilTick; private static int _superGrowBeginAuditSeq; private static ChemistryStation? _superGrowBeginStation; private static int _superGrowBeginStationSeq; private static string? _lastSelectedRecipeProductId; private static string? _lastSelectedRecipeTitle; private static string? _lastSelectedRecipeId; private static int _lastSelectedAtTick; private static bool _stationItemInitializePatchInfoDumped; private static readonly Dictionary<int, int> _chemCanvasDumpMaskByInstanceId = new Dictionary<int, int>(); private const int TrashAuditWindowMs = 60000; private const int TrashAuditMaxLogs = 50; private static int _trashAuditUntilTick; private static int _trashAuditSeq; private static int _trashAuditTrashManagerLogged; private static int _trashAuditGetTrashPrefabLogged; private static int _trashAuditTrashItemStartLogged; private static bool _trashAuditHasStationPos; private static Vector3 _trashAuditStationPos; private static readonly HashSet<string> _trashAuditSeenTrashIds = new HashSet<string>(); private static readonly HashSet<string> _trashAuditSeenGetTrashPrefabIds = new HashSet<string>(); private static bool _trashAuditTrashPrefabsDumped; private static TrashManager? _trashAuditManager; private const int BeakerAuditWindowMs = 30000; private const int BeakerAuditMaxLogs = 80; private const float BeakerAuditMinLoggedLevelDelta = 0.05f; private const float BeakerAuditLevelEdgeEpsilon = 0.01f; private const float BeakerAuditMinLoggedColorDelta = 0.02f; private const int BeakerContentsAuditMaxLogs = 120; private const int BeakerContentsAuditMinIntervalMs = 250; private const float BeakerContentsAuditMinTotalDelta = 0.02f; private static int _beakerAuditUntilTick; private static int _beakerAuditSeq; private static int _beakerAuditLiquidColorLogged; private static int _beakerAuditLiquidLevelLogged; private static int _beakerContentsAuditLogged; private static bool _beakerAuditHasStationPos; private static Vector3 _beakerAuditStationPos; private static readonly HashSet<int> _beakerAuditSeenContainerIds = new HashSet<int>(); private static readonly HashSet<int> _beakerAuditTrackedContainerIds = new HashSet<int>(); private static readonly Dictionary<int, float> _beakerAuditLastLoggedLevel = new Dictionary<int, float>(); private static readonly Dictionary<int, Color> _beakerAuditLastLoggedColor = new Dictionary<int, Color>(); private static readonly Dictionary<int, int> _beakerContentsAuditLastTickByFillableId = new Dictionary<int, int>(); private static readonly Dictionary<int, float> _beakerContentsAuditLastTotalByFillableId = new Dictionary<int, float>(); private static readonly Dictionary<int, string> _beakerContentsAuditLastLabelByFillableId = new Dictionary<int, string>(); private static bool _beakerAuditExpiredLogged; private const int ChemCanvasDump_AwakePostfix = 1; private const int ChemCanvasDump_OpenPrefix = 2; private const int ChemCanvasDump_UiAwakePostfix = 4; private const int ChemCanvasDump_UiOpenPrefix = 8; private const string PgrBottleTrashId = "supergrow_pgr_bottle"; private const string SpeedGrowBottleTrashId = "supergrow_speedgrow_bottle"; private const string FertilizerBottleTrashId = "supergrow_fertilizer_bottle"; private const string SuperGrowBottleTrashId = "supergrow_bottle"; private static GameObject? _prefabCacheRoot; private static bool _baseStationItemPrefabsEnsured; private static readonly Dictionary<string, StationItem> _stationItemPrefabByAdditiveId = new Dictionary<string, StationItem>(); private static int _il2cppTrashPrefabsEnsuredForManagerId; private static readonly Dictionary<string, TrashItem> _il2cppBottleTrashPrefabByAdditiveId = new Dictionary<string, TrashItem>(StringComparer.OrdinalIgnoreCase); private static bool _loggedIl2CppTrashPrefabInjectionException; private static bool _loggedIl2CppTrashPrefabEnsureException; private static int _pendingStationTrashReskinExpireTick; private static readonly List<PendingTrashReskin> _pendingStationTrashReskins = new List<PendingTrashReskin>(); private static readonly Dictionary<string, GameObject> _pourablePrefabs = new Dictionary<string, GameObject>(); private static readonly Dictionary<string, Color> _additiveColors = new Dictionary<string, Color> { { "pgr", new Color(1f, 0.506f, 0.506f, 1f) }, { "speedgrow", new Color(0.506f, 0.812f, 1f, 1f) }, { "fertilizer", new Color(0.639f, 1f, 0.506f, 1f) }, { "supergrow", SuperGrowVisuals.PourColor } }; private const float LiquidScale = 0.65f; public static void Reset() { _superGrowRecipe = null; _additivesPatched = false; _loggedMissingStationItemTemplate = false; _loggedRegistryStart = false; _loggedRecipeNotReady = false; _chemCanvasDumpMaskByInstanceId.Clear(); _baseStationItemPrefabsEnsured = false; _il2cppTrashPrefabsEnsuredForManagerId = 0; } private static void BeginBeakerAuditWindow(int seq, ChemistryStation? station) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) _beakerAuditSeq = seq; _beakerAuditUntilTick = Environment.TickCount + 30000; _beakerAuditLiquidColorLogged = 0; _beakerAuditLiquidLevelLogged = 0; _beakerContentsAuditLogged = 0; _beakerAuditSeenContainerIds.Clear(); _beakerAuditTrackedContainerIds.Clear(); _beakerAuditLastLoggedLevel.Clear(); _beakerAuditLastLoggedColor.Clear(); _beakerContentsAuditLastTickByFillableId.Clear(); _beakerContentsAuditLastTotalByFillableId.Clear(); _beakerContentsAuditLastLabelByFillableId.Clear(); _beakerAuditExpiredLogged = false; if ((Object)(object)station != (Object)null && (Object)(object)((Component)station).transform != (Object)null) { _beakerAuditHasStationPos = true; _beakerAuditStationPos = ((Component)station).transform.position; } else { _beakerAuditHasStationPos = false; _beakerAuditStationPos = Vector3.zero; } string value = (_beakerAuditHasStationPos ? ((object)Unsafe.As<Vector3, Vector3>(ref _beakerAuditStationPos)/*cast due to .constrained prefix*/).ToString() : "<unknown>"); MelonLogger.Msg($"SuperGrow beaker audit #{seq}: enabled for {30000}ms stationPos={value}"); try { if ((Object)(object)station != (Object)null) { DumpNearbyLiquidContainersOnce(station, "BeginBeakerAuditWindow"); } } catch { } } private static bool IsBeakerAuditActive() { if (_beakerAuditUntilTick == 0) { return false; } if (Environment.TickCount - _beakerAuditUntilTick < 0) { return true; } if (!_beakerAuditExpiredLogged) { _beakerAuditExpiredLogged = true; try { MelonLogger.Msg($"SuperGrow beaker audit #{_beakerAuditSeq}: expired (levelLogs={_beakerAuditLiquidLevelLogged}/{80} colorLogs={_beakerAuditLiquidColorLogged}/{80} trackedIds={_beakerAuditTrackedContainerIds.Count})"); } catch { } } _beakerAuditUntilTick = 0; return false; } private static bool IsNearBeakerAuditedStation(Vector3 position) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (!_beakerAuditHasStationPos) { return true; } return Vector3.Distance(position, _beakerAuditStationPos) <= 35f; } private static string GetTransformPath(Transform? transform) { if ((Object)(object)transform == (Object)null) { return "<null>"; } StringBuilder stringBuilder = new StringBuilder(); Transform val = transform; while ((Object)(object)val != (Object)null) { stringBuilder.Insert(0, "/" + ((Object)val).name); val = val.parent; } return (stringBuilder.Length == 0) ? "<empty>" : stringBuilder.ToString(); } private static bool ShouldTrackLiquidContainer(string goName, string path) { if (goName == "Liquid" && path.Contains("/Beaker(") && path.EndsWith("/Beaker/Liquid")) { return true; } if (goName == "Pourable" && path.EndsWith("/Pourable") && path.Contains("/ItemContainer/")) { return true; } return false; } private static bool ColorsApproximatelyEqual(Color a, Color b) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) return Mathf.Abs(a.r - b.r) < 0.02f && Mathf.Abs(a.g - b.g) < 0.02f && Mathf.Abs(a.b - b.b) < 0.02f && Mathf.Abs(a.a - b.a) < 0.02f; } private static void DumpNearbyLiquidContainersOnce(ChemistryStation station, string reason) { //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) try { Il2CppArrayBase<LiquidContainer> componentsInChildren = ((Component)station).GetComponentsInChildren<LiquidContainer>(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { MelonLogger.Msg($"SuperGrow beaker audit #{_beakerAuditSeq}: no LiquidContainers found ({reason})"); return; } MelonLogger.Msg($"SuperGrow beaker audit #{_beakerAuditSeq}: LiquidContainers near station ({reason}) count={componentsInChildren.Length}"); int num = 0; for (int i = 0; i < componentsInChildren.Length; i++) { if (num >= 25) { break; } LiquidContainer val = componentsInChildren[i]; if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || (Object)(object)((Component)val).transform == (Object)null) { continue; } Vector3 position = ((Component)val).transform.position; if (IsNearBeakerAuditedStation(position)) { int instanceID = ((Object)val).GetInstanceID(); string text = ((Object)((Component)val).gameObject).name ?? "<unnamed>"; string transformPath = GetTransformPath(((Component)val).transform); string value = (_beakerAuditHasStationPos ? Vector3.Distance(position, _beakerAuditStationPos).ToString("0.0") : "<n/a>"); MelonLogger.Msg($" - containerId={instanceID} name={text} dist={value} level={val.CurrentLiquidLevel:0.###}/{val.MaxLevel:0.###} color=({val.LiquidColor.r:0.###},{val.LiquidColor.g:0.###},{val.LiquidColor.b:0.###},{val.LiquidColor.a:0.###}) path={transformPath}"); if (ShouldTrackLiquidContainer(text, transformPath)) { _beakerAuditTrackedContainerIds.Add(instanceID); } num++; } } } catch (Exception ex) { MelonLogger.Error("SuperGrow beaker audit: failed to dump LiquidContainers (" + reason + "): " + ex.Message); } } [HarmonyPatch(typeof(Fillable), "ResetContents")] [HarmonyPostfix] private static void Fillable_ResetContents_DebugPostfix(Fillable __instance) { if (!IsBeakerAuditActive() || _beakerContentsAuditLogged >= 120) { return; } try { if (!((Object)(object)__instance == (Object)null) && IsChemistryBeakerFillable(__instance)) { int instanceID = ((Object)__instance).GetInstanceID(); _beakerContentsAuditLastTickByFillableId.Remove(instanceID); _beakerContentsAuditLastTotalByFillableId.Remove(instanceID); _beakerContentsAuditLastLabelByFillableId.Remove(instanceID); _beakerContentsAuditLogged++; MelonLogger.Msg($"SuperGrow beaker audit #{_beakerAuditSeq}: Fillable.ResetContents fillableId={instanceID}"); } } catch (Exception ex) { MelonLogger.Error("SuperGrow beaker audit: Fillable.ResetContents logging failed: " + ex.Message); } } [HarmonyPatch(typeof(Fillable), "AddLiquid", new Type[] { typeof(string), typeof(float), typeof(Color) })] [HarmonyPostfix] private static void Fillable_AddLiquid_DebugPostfix(Fillable __instance, string label, float volume, Color color) { //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) if (!IsBeakerAuditActive() || _beakerContentsAuditLogged >= 120) { return; } try { if (!((Object)(object)__instance == (Object)null) && IsChemistryBeakerFillable(__instance)) { int instanceID = ((Object)__instance).GetInstanceID(); int tickCount = Environment.TickCount; float totalLiquidVolume = __instance.GetTotalLiquidVolume(); int value; bool flag = _beakerContentsAuditLastTickByFillableId.TryGetValue(instanceID, out value); float value2; bool flag2 = _beakerContentsAuditLastTotalByFillableId.TryGetValue(instanceID, out value2); string value3; bool flag3 = _beakerContentsAuditLastLabelByFillableId.TryGetValue(instanceID, out value3) && string.Equals(value3, label, StringComparison.Ordinal); bool flag4 = flag2 && Mathf.Abs(totalLiquidVolume - value2) < 0.02f; bool flag5 = flag && tickCount - value < 250; if (!(flag3 && flag4 && flag5)) { _beakerContentsAuditLastTickByFillableId[instanceID] = tickCount; _beakerContentsAuditLastTotalByFillableId[instanceID] = totalLiquidVolume; _beakerContentsAuditLastLabelByFillableId[instanceID] = label; float liquidVolume = __instance.GetLiquidVolume("pgr"); float liquidVolume2 = __instance.GetLiquidVolume("speedgrow"); float liquidVolume3 = __instance.GetLiquidVolume("fertilizer"); float liquidVolume4 = __instance.GetLiquidVolume("supergrow"); float value4 = (string.IsNullOrWhiteSpace(label) ? 0f : __instance.GetLiquidVolume(label)); float liquidCapacity_L = __instance.LiquidCapacity_L; LiquidContainer liquidContainer = __instance.LiquidContainer; Color val = (((Object)(object)liquidContainer != (Object)null) ? liquidContainer.LiquidColor : Color.clear); _beakerContentsAuditLogged++; MelonLogger.Msg($"SuperGrow beaker audit #{_beakerAuditSeq}: Fillable.AddLiquid label={label} delta={volume:0.###} addColor=({color.r:0.###},{color.g:0.###},{color.b:0.###},{color.a:0.###}) total={totalLiquidVolume:0.###}/{liquidCapacity_L:0.###} pgr={liquidVolume:0.###} speedgrow={liquidVolume2:0.###} fertilizer={liquidVolume3:0.###} supergrow={liquidVolume4:0.###} labelVol={value4:0.###} beakerColor=({val.r:0.###},{val.g:0.###},{val.b:0.###},{val.a:0.###}) fillableId={instanceID}"); } } } catch (Exception ex) { MelonLogger.Error("SuperGrow beaker audit: Fillable.AddLiquid logging failed: " + ex.Message); } } private static StationRecipe? GetCachedSelectedRecipe(ChemistryStationInterface canvas) { try { RectTransform recipeContainer = canvas.RecipeContainer; if ((Object)(object)recipeContainer == (Object)null) { return null; } Il2CppArrayBase<StationRecipeEntry> componentsInChildren = ((Component)recipeContainer).GetComponentsInChildren<StationRecipeEntry>(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { return null; } for (int i = 0; i < componentsInChildren.Length; i++) { StationRecipeEntry val = componentsInChildren[i]; if ((Object)(object)val == (Object)null) { continue; } StationRecipe recipe = val.Recipe; if (!((Object)(object)recipe == (Object)null)) { string text = SafeGetProductId(recipe); if (text == "supergrow") { return recipe; } } } } catch { } return null; } private static string SafeGetItemDefinitionId(ItemDefinition? def) { try { return ((def != null) ? ((BaseItemDefinition)def).ID : null) ?? "<null>"; } catch { return "<error>"; } } private static void LogRecipeIngredients(StationRecipe? recipe, int seq) { try { if ((Object)(object)recipe == (Object)null) { MelonLogger.Msg($"SuperGrow Begin audit #{seq}: recipe=<null>"); return; } string value = SafeGetStationRecipeId(recipe); List<IngredientQuantity> ingredients = recipe.Ingredients; int value2 = ingredients?.Count ?? (-1); MelonLogger.Msg($"SuperGrow Begin audit #{seq}: recipeId={value} ingredientCount={value2}"); if (ingredients == null) { return; } for (int i = 0; i < ingredients.Count; i++) { IngredientQuantity val = ingredients[i]; if (val == null) { MelonLogger.Msg($"SuperGrow Begin audit #{seq}: ingredient[{i}]=<null>"); continue; } int quantity = val.Quantity; List<ItemDefinition> items = val.Items; int value3 = items?.Count ?? (-1); string value4 = ((items != null && items.Count > 0) ? SafeGetItemDefinitionId(items[0]) : "<none>"); MelonLogger.Msg($"SuperGrow Begin audit #{seq}: ingredient[{i}] qty={quantity} items={value3} first={value4}"); if (items == null) { continue; } for (int j = 0; j < items.Count; j++) { ItemDefinition val2 = items[j]; if (!((Object)(object)val2 == (Object)null)) { string value5 = SafeGetItemDefinitionId(val2); LogItemDefinitionPrefabState(val2, seq, $"ingredient[{i}].items[{j}] ({value5})"); } } } } catch (Exception ex) { MelonLogger.Error($"SuperGrow Begin audit #{seq}: failed to log recipe ingredients: {ex.Message}"); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } private static void LogItemDefinitionPrefabState(ItemDefinition def, int seq, string label) { try { StorableItemDefinition val = ((Il2CppObjectBase)def).TryCast<StorableItemDefinition>(); if ((Object)(object)val == (Object)null) { MelonLogger.Msg($"SuperGrow Begin audit #{seq}: {label} type={((object)def).GetType().FullName} storable=<null>"); return; } StationItem stationItem = val.StationItem; StoredItem storedItem = val.StoredItem; Equippable equippable = def.Equippable; string value = (((Object)(object)stationItem == (Object)null) ? "<null>" : $"{((Object)((Component)stationItem).gameObject).name} activeSelf={((Component)stationItem).gameObject.activeSelf} modules={SafeGetStationItemModuleCount(stationItem)}"); string value2 = (((Object)(object)storedItem == (Object)null) ? "<null>" : ((Object)storedItem).name); string value3 = (((Object)(object)equippable == (Object)null) ? "<null>" : ((Object)equippable).name); MelonLogger.Msg($"SuperGrow Begin audit #{seq}: {label} type={((object)def).GetType().FullName} stationItem={value} storedItem={value2} equippable={value3}"); } catch (Exception ex) { MelonLogger.Error($"SuperGrow Begin audit #{seq}: failed to inspect {label}: {ex.Message}"); } } private static int SafeGetStationItemModuleCount(StationItem stationItem) { try { return stationItem.Modules?.Count ?? (-1); } catch { return -1; } } private static void LogChemistryStationSlotState(ChemistryStation? station, int seq, string tag) { try { if ((Object)(object)station == (Object)null) { MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): station=<null>"); return; } ChemistryCookOperation currentCookOperation = station.CurrentCookOperation; string value = ((currentCookOperation == null) ? "<null>" : (currentCookOperation.RecipeID ?? "<null>")); MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): cookOpId={value}"); if (station.IngredientSlots != null) { for (int i = 0; i < ((Il2CppArrayBase<ItemSlot>)(object)station.IngredientSlots).Length; i++) { ItemSlot val = ((Il2CppArrayBase<ItemSlot>)(object)station.IngredientSlots)[i]; ItemInstance val2 = ((val != null) ? val.ItemInstance : null); ItemDefinition val3 = ((val2 != null) ? val2.Definition : null); string value2 = (((Object)(object)val3 == (Object)null) ? "<null>" : SafeGetItemDefinitionId(val3)); int value3 = ((val2 != null) ? ((BaseItemInstance)val2).Quantity : 0); MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): slot[{i}] id={value2} qty={value3}"); } } else { MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): IngredientSlots=<null>"); } } catch (Exception ex) { MelonLogger.Error($"SuperGrow Begin audit #{seq} ({tag}) failed: {ex.Message}"); } } private static void LogChemistryStationIngredientTransforms(ChemistryStation station, int seq, string tag) { try { Il2CppReferenceArray<Transform> ingredientTransforms = station.IngredientTransforms; int value = ((Il2CppArrayBase<Transform>)(object)ingredientTransforms)?.Length ?? (-1); MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): ingredientTransforms={value}"); if (ingredientTransforms == null) { return; } for (int i = 0; i < ((Il2CppArrayBase<Transform>)(object)ingredientTransforms).Length; i++) { Transform val = ((Il2CppArrayBase<Transform>)(object)ingredientTransforms)[i]; if ((Object)(object)val == (Object)null) { MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): transform[{i}]=<null>"); continue; } int childCount = val.childCount; MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): transform[{i}] name={((Object)val).name} childCount={childCount}"); for (int j = 0; j < childCount && j < 6; j++) { Transform child = val.GetChild(j); MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): - child[{j}] name={((Object)child).name} activeSelf={((Component)child).gameObject.activeSelf}"); } } } catch (Exception ex) { MelonLogger.Error($"SuperGrow Begin audit #{seq} ({tag}): failed to inspect ingredient transforms: {ex.Message}"); } } private static void DumpChemistryStationInterfaceStateOnce(ChemistryStationInterface canvas, string tag, int stageMask) { if (!((Object)(object)canvas == (Object)null)) { int instanceID = ((Object)canvas).GetInstanceID(); if (!_chemCanvasDumpMaskByInstanceId.TryGetValue(instanceID, out var value) || (value & stageMask) == 0) { _chemCanvasDumpMaskByInstanceId[instanceID] = value | stageMask; DumpChemistryStationInterfaceState(canvas, tag); } } } private static void DumpChemistryStationInterfaceUiStateOnce(ChemistryStationInterface canvas, string tag, int stageMask) { if (!((Object)(object)canvas == (Object)null)) { int instanceID = ((Object)canvas).GetInstanceID(); if (!_chemCanvasDumpMaskByInstanceId.TryGetValue(instanceID, out var value) || (value & stageMask) == 0) { _chemCanvasDumpMaskByInstanceId[instanceID] = value | stageMask; DumpChemistryStationInterfaceUiState(canvas, tag); } } } private static void DumpChemistryStationInterfaceState(ChemistryStationInterface canvas, string tag) { try { int instanceID = ((Object)canvas).GetInstanceID(); object recipes = canvas.Recipes; int? num = TryGetCount(recipes); bool value = ListContainsSuperGrowRecipe(recipes); Type typeFromHandle = typeof(ChemistryStationInterface); FieldInfo field = typeFromHandle.GetField("recipeEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); PropertyInfo propertyInfo = ((field == null) ? typeFromHandle.GetProperty("recipeEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : null); object obj = null; if (field != null) { obj = field.GetValue(canvas); } else if (propertyInfo != null) { obj = propertyInfo.GetValue(canvas); } int? num2 = TryGetCount(obj); bool value2 = ListContainsSuperGrowRecipeEntry(obj); MelonLogger.Msg($"ChemistryStationInterface audit ({tag}): canvasId={instanceID} recipes={((recipes == null) ? "<null>" : (num?.ToString() ?? "<unknown>"))} hasSuperGrowRecipe={value} recipeEntriesField={((field != null) ? "ok" : ((propertyInfo != null) ? "ok(prop)" : "<missing>"))} recipeEntries={((obj == null) ? "<null>" : (num2?.ToString() ?? "<unknown>"))} hasSuperGrowEntry={value2}"); } catch (Exception ex) { MelonLogger.Error("ChemistryStationInterface audit failed (" + tag + "): " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } private static void DumpChemistryStationInterfaceUiState(ChemistryStationInterface canvas, string tag) { try { int instanceID = ((Object)canvas).GetInstanceID(); RectTransform recipeContainer = canvas.RecipeContainer; if ((Object)(object)recipeContainer == (Object)null) { MelonLogger.Msg($"ChemistryStationInterface UI audit ({tag}): canvasId={instanceID} RecipeContainer=<null>"); return; } Il2CppArrayBase<StationRecipeEntry> componentsInChildren = ((Component)recipeContainer).GetComponentsInChildren<StationRecipeEntry>(true); int value = componentsInChildren?.Length ?? 0; MelonLogger.Msg($"ChemistryStationInterface UI audit ({tag}): canvasId={instanceID} recipeContainerChildren={((Transform)recipeContainer).childCount} entryComponents={value}"); if (componentsInChildren == null || componentsInChildren.Length == 0) { return; } int num = 0; for (int i = 0; i < componentsInChildren.Length; i++) { if (num >= 12) { break; } StationRecipeEntry val = componentsInChildren[i]; if (!((Object)(object)val == (Object)null)) { string value2; try { value2 = (((Object)(object)val.TitleLabel == (Object)null) ? "<null>" : (((TMP_Text)val.TitleLabel).text ?? "<null>")); } catch { value2 = "<error>"; } string value3 = SafeGetProductId(val.Recipe); MelonLogger.Msg($"ChemistryStationInterface UI entry ({tag}): idx={i} title={value2} productId={value3}"); num++; } } } catch (Exception ex) { MelonLogger.Error("ChemistryStationInterface UI audit failed (" + tag + "): " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } public static void DumpStationItemInitializePatchesOnce(string reason) { if (!_stationItemInitializePatchInfoDumped) { _stationItemInitializePatchInfoDumped = true; DumpStationItemInitializePatchInfo(reason); } } private static void DumpStationItemInitializePatchInfo(string reason) { try { MethodInfo methodInfo = AccessTools.Method(typeof(StationItem), "Initialize", new Type[1] { typeof(StorableItemDefinition) }, (Type[])null) ?? AccessTools.Method(typeof(StationItem), "Initialize", (Type[])null, (Type[])null); if (methodInfo == null) { MelonLogger.Warning("Could not resolve StationItem.Initialize method for patch audit (" + reason + ")"); return; } Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo); if (patchInfo == null) { MelonLogger.Msg("StationItem.Initialize patch audit (" + reason + "): no Harmony patches found"); return; } string text = ((patchInfo.Owners != null && patchInfo.Owners.Count > 0) ? string.Join(", ", patchInfo.Owners) : "<none>"); MelonLogger.Msg("StationItem.Initialize patch audit (" + reason + "): owners=" + text); LogPatchList("prefix", patchInfo.Prefixes); LogPatchList("postfix", patchInfo.Postfixes); LogPatchList("transpiler", patchInfo.Transpilers); LogPatchList("finalizer", patchInfo.Finalizers); } catch (Exception ex) { MelonLogger.Error("Failed to dump StationItem.Initialize patch audit (" + reason + "): " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } private static void LogPatchList(string kind, IReadOnlyCollection<Patch> patches) { if (patches == null || patches.Count == 0) { MelonLogger.Msg("StationItem.Initialize " + kind + ": <none>"); return; } MelonLogger.Msg($"StationItem.Initialize {kind}: count={patches.Count}"); foreach (Patch patch in patches) { MethodInfo patchMethod = patch.PatchMethod; string value = ((patchMethod == null) ? "<null>" : ((patchMethod.DeclaringType == null) ? patchMethod.Name : (patchMethod.DeclaringType.FullName + "." + patchMethod.Name))); MelonLogger.Msg($" - owner={patch.owner} prio={patch.priority} idx={patch.index} method={value}"); } } private static int? TryGetCount(object? listObj) { if (listObj == null) { return null; } Type type = listObj.GetType(); PropertyInfo property = type.GetProperty("Count"); if (property != null && property.PropertyType == typeof(int)) { return (int?)property.GetValue(listObj); } MethodInfo method = type.GetMethod("get_Count", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null && method.ReturnType == typeof(int)) { return (int?)method.Invoke(listObj, null); } return null; } private static object? TryGetListItem(object? listObj, int index) { if (listObj == null) { return null; } Type type = listObj.GetType(); PropertyInfo property = type.GetProperty("Item"); if (property != null) { try { return property.GetValue(listObj, new object[1] { index }); } catch { } } MethodInfo method = type.GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { try { return method.Invoke(listObj, new object[1] { index }); } catch { } } return null; } private static bool ListContainsSuperGrowRecipe(object? recipesObj) { if (recipesObj == null) { return false; } int? num = TryGetCount(recipesObj); bool flag; if (num.HasValue) { int valueOrDefault = num.GetValueOrDefault(); if (valueOrDefault > 0) { flag = false; goto IL_0037; } } flag = true; goto IL_0037; IL_0037: if (flag) { return false; } for (int i = 0; i < num; i++) { object obj = TryGetListItem(recipesObj, i); if (obj != null && TryGetStationRecipeProductId(obj, out string productId) && productId == "supergrow") { return true; } } return false; } private static bool ListContainsSuperGrowRecipeEntry(object? entriesObj) { if (entriesObj == null) { return false; } int? num = TryGetCount(entriesObj); bool flag; if (num.HasValue) { int valueOrDefault = num.GetValueOrDefault(); if (valueOrDefault > 0) { flag = false; goto IL_0037; } } flag = true; goto IL_0037; IL_0037: if (flag) { return false; } for (int i = 0; i < num; i++) { object obj = TryGetListItem(entriesObj, i); if (obj != null) { object obj2 = obj.GetType().GetProperty("Recipe", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj); if (obj2 != null && TryGetStationRecipeProductId(obj2, out string productId) && productId == "supergrow") { return true; } } } return false; } private static bool TryGetStationRecipeProductId(object recipeObj, out string? productId) { productId = null; try { MemberInfo memberInfo = (MemberInfo)(((object)recipeObj.GetType().GetProperty("Product", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) ?? ((object)recipeObj.GetType().GetField("Product", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))); if (1 == 0) { } object obj = ((memberInfo is PropertyInfo propertyInfo) ? propertyInfo.GetValue(recipeObj) : ((!(memberInfo is FieldInfo fieldInfo)) ? null : fieldInfo.GetValue(recipeObj))); if (1 == 0) { } object obj2 = obj; if (obj2 == null) { return false; } MemberInfo memberInfo2 = (MemberInfo)(((object)obj2.GetType().GetProperty("Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) ?? ((object)obj2.GetType().GetField("Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))); if (1 == 0) { } obj = ((memberInfo2 is PropertyInfo propertyInfo2) ? propertyInfo2.GetValue(obj2) : ((!(memberInfo2 is FieldInfo fieldInfo2)) ? null : fieldInfo2.GetValue(obj2))); if (1 == 0) { } object obj3 = obj; if (obj3 == null) { return false; } PropertyInfo property = obj3.GetType().GetProperty("ID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.PropertyType == typeof(string)) { productId = property.GetValue(obj3) as string; return productId != null; } FieldInfo field = obj3.GetType().GetField("ID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(string)) { productId = field.GetValue(obj3) as string; return productId != null; } MethodInfo method = obj3.GetType().GetMethod("get_ID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null && method.ReturnType == typeof(string)) { productId = method.Invoke(obj3, null) as string; return productId != null; } } catch { } return false; } private static void BeginTrashAuditWindow(int seq, ChemistryStation? station) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) _trashAuditSeq = seq; _trashAuditUntilTick = Environment.TickCount + 60000; _trashAuditTrashManagerLogged = 0; _trashAuditGetTrashPrefabLogged = 0; _trashAuditTrashItemStartLogged = 0; _trashAuditSeenTrashIds.Clear(); _trashAuditSeenGetTrashPrefabIds.Clear(); _trashAuditTrashPrefabsDumped = false; if ((Object)(object)station != (Object)null && (Object)(object)((Component)station).transform != (Object)null) { _trashAuditHasStationPos = true; _trashAuditStationPos = ((Component)station).transform.position; } else { _trashAuditHasStationPos = false; _trashAuditStationPos = Vector3.zero; } string value = (_trashAuditHasStationPos ? ((object)Unsafe.As<Vector3, Vector3>(ref _trashAuditStationPos)/*cast due to .constrained prefix*/).ToString() : "<unknown>"); MelonLogger.Msg($"SuperGrow trash audit #{seq}: enabled for {60000}ms stationPos={value}"); try { if ((Object)(object)_trashAuditManager == (Object)null) { _trashAuditManager = Object.FindObjectOfType<TrashManager>(); } DumpTrashPrefabsOnce("BeginTrashAuditWindow", _trashAuditManager); } catch { } } private static bool IsTrashAuditActive() { return _trashAuditUntilTick != 0 && Environment.TickCount - _trashAuditUntilTick < 0; } private static bool IsNearAuditedStation(Vector3 position) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (!_trashAuditHasStationPos) { return true; } return Vector3.Distance(position, _trashAuditStationPos) <= 35f; } private static void DumpTrashPrefabsOnce(string reason, TrashManager? manager) { if (_trashAuditTrashPrefabsDumped) { return; } if ((Object)(object)manager == (Object)null) { MelonLogger.Msg($"SuperGrow trash audit #{_trashAuditSeq}: TrashManager not found for TrashPrefabs dump ({reason})"); return; } _trashAuditTrashPrefabsDumped = true; try { Il2CppReferenceArray<TrashItem> trashPrefabs = manager.TrashPrefabs; int value = ((Il2CppArrayBase<TrashItem>)(object)trashPrefabs)?.Length ?? 0; MelonLogger.Msg($"SuperGrow trash audit #{_trashAuditSeq}: TrashPrefabs dump ({reason}) total={value}"); if (trashPrefabs != null) { for (int i = 0; i < ((Il2CppArrayBase<TrashItem>)(object)trashPrefabs).Length; i++) { TrashItem val = ((Il2CppArrayBase<TrashItem>)(object)trashPrefabs)[i]; string value2 = (((Object)(object)val == (Object)null) ? "<null>" : (val.ID ?? "<null-id>")); string value3 = (((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null) ? "<null>" : (((Object)((Component)val).gameObject).name ?? "<unnamed>")); MelonLogger.Msg($" - [{i}] id={value2} name={value3}"); } } } catch (Exception ex) { MelonLogger.Error("SuperGrow trash audit: TrashPrefabs dump failed (" + reason + "): " + ex.Message); } } [HarmonyPatch(typeof(ChemistryStation), "CreateTrash")] [HarmonyPrefix] private static void ChemistryStation_CreateTrash_DebugPrefix(ChemistryStation __instance, List<StationItem> mixerItems) { if (!IsTrashAuditActive()) { return; } try { ChemistryCookOperation val = ((__instance != null) ? __instance.CurrentCookOperation : null); string value = ((val == null) ? "<null-op>" : (val.RecipeID ?? "<null>")); int value2 = mixerItems?.Count ?? (-1); MelonLogger.Msg($"SuperGrow trash audit #{_trashAuditSeq}: ChemistryStation.CreateTrash recipeId={value} mixerItems={value2}"); if (mixerItems == null) { return; } int num = Math.Min(8, mixerItems.Count); for (int i = 0; i < num; i++) { StationItem val2 = mixerItems[i]; if ((Object)(object)val2 == (Object)null || (Object)(object)((Component)val2).gameObject == (Object)null) { MelonLogger.Msg($" - mixer[{i}]=<null>"); continue; } string value3 = ((Object)((Component)val2).gameObject).name ?? "<unnamed>"; string value4 = (((Object)(object)val2.TrashPrefab == (Object)null) ? "<null>" : (val2.TrashPrefab.ID ?? "<null-id>")); MelonLogger.Msg($" - mixer[{i}] name={value3} trashId={value4}"); } } catch (Exception ex) { MelonLogger.Error("SuperGrow trash audit: ChemistryStation.CreateTrash logging failed: " + ex.Message); } } [HarmonyPatch(typeof(TrashManager), "Start")] [HarmonyPostfix] private static void TrashManager_Start_DebugPostfix(TrashManager __instance) { _trashAuditManager = __instance; if (IsTrashAuditActive()) { DumpTrashPrefabsOnce("TrashManager.Start", __instance); } } [HarmonyPatch(typeof(TrashManager), "CreateTrashItem", new Type[] { typeof(string), typeof(Vector3), typeof(Quaternion), typeof(Vector3), typeof(string), typeof(bool) })] [HarmonyPrefix] private static void TrashManager_CreateTrashItem_DebugPrefix(string id, Vector3 posiiton, Quaternion rotation, Vector3 initialVelocity, string guid, bool startKinematic) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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) if (!IsTrashAuditActive() || _trashAuditTrashManagerLogged >= 50 || !IsNearAuditedStation(posiiton)) { return; } try { string text = id ?? "<null>"; if (_trashAuditSeenTrashIds.Add(text)) { _trashAuditTrashManagerLogged++; string value = (_trashAuditHasStationPos ? Vector3.Distance(posiiton, _trashAuditStationPos).ToString("0.0") : "<n/a>"); MelonLogger.Msg($"SuperGrow trash audit #{_trashAuditSeq}: TrashManager.CreateTrashItem id={text} pos={posiiton} dist={value}"); } } catch (Exception ex) { MelonLogger.Error("SuperGrow trash audit: TrashManager.CreateTrashItem logging failed: " + ex.Message); } } [HarmonyPatch(typeof(TrashManager), "GetTrashPrefab", new Type[] { typeof(string) })] [HarmonyPostfix] private static void TrashManager_GetTrashPrefab_DebugPostfix(TrashManager __instance, string id, TrashItem __result) { if (!IsTrashAuditActive() || _trashAuditGetTrashPrefabLogged >= 50) { return; } try { string text = id ?? "<null>"; if (!_trashAuditSeenGetTrashPrefabIds.Add(text)) { return; } string value = (((Object)(object)__result == (Object)null) ? "<null>" : (__result.ID ?? "<null-id>")); string value2 = (((Object)(object)__result == (Object)null || (Object)(object)((Component)__result).gameObject == (Object)null) ? "<null>" : (((Object)((Component)__result).gameObject).name ?? "<unnamed>")); Il2CppReferenceArray<TrashItem> val = (((Object)(object)__instance == (Object)null) ? null : __instance.TrashPrefabs); int value3 = ((Il2CppArrayBase<TrashItem>)(object)val)?.Length ?? 0; int value4 = -1; if (val != null) { for (int i = 0; i < ((Il2CppArrayBase<TrashItem>)(object)val).Length; i++) { TrashItem val2 = ((Il2CppArrayBase<TrashItem>)(object)val)[i]; if ((Object)(object)val2 != (Object)null && val2.ID == text) { value4 = i; break; } } } _trashAuditGetTrashPrefabLogged++; MelonLogger.Msg($"SuperGrow trash audit #{_trashAuditSeq}: TrashManager.GetTrashPrefab id={text} -> resultId={value} resultName={value2} trashPrefabsIndex={value4} total={value3}"); } catch (Exception ex) { MelonLogger.Error("SuperGrow trash audit: TrashManager.GetTrashPrefab logging failed: " + ex.Message); } } [HarmonyPatch(typeof(TrashItem), "Start")] [HarmonyPostfix] private static void TrashItem_Start_DebugPostfix(TrashItem __instance) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) if (!IsTrashAuditActive() || _trashAuditTrashItemStartLogged >= 50) { return; } try { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).gameObject == (Object)null)) { Vector3 val = (((Object)(object)((Component)__instance).transform != (Object)null) ? ((Component)__instance).transform.position : Vector3.zero); if (IsNearAuditedStation(val)) { _trashAuditTrashItemStartLogged++; string value = __instance.ID ?? "<null>"; string value2 = ((Object)((Component)__instance).gameObject).name ?? "<unnamed>"; string value3 = (_trashAuditHasStationPos ? Vector3.Distance(val, _trashAuditStationPos).ToString("0.0") : "<n/a>"); MelonLogger.Msg($"SuperGrow trash audit #{_trashAuditSeq}: TrashItem.Start id={value} name={value2} pos={val} dist={value3}"); } } } catch (Exception ex) { MelonLogger.Error("SuperGrow trash audit: TrashItem.Start logging failed: " + ex.Message); } } private static Transform GetOrCreatePrefabCacheRoot() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown if ((Object)(object)_prefabCacheRoot != (Object)null) { return _prefabCacheRoot.transform; } _prefabCacheRoot = new GameObject("SuperGrow_PrefabCache"); Object.DontDestroyOnLoad((Object)(object)_prefabCacheRoot); _prefabCacheRoot.SetActive(false); return _prefabCacheRoot.transform; } private static bool TryGetBottleTrashId(string additiveId, out string trashId) { trashId = null; if (string.Equals(additiveId, "pgr", StringComparison.OrdinalIgnoreCase)) { trashId = "supergrow_pgr_bottle"; return true; } if (string.Equals(additiveId, "speedgrow", StringComparison.OrdinalIgnoreCase)) { trashId = "supergrow_speedgrow_bottle"; return true; } if (string.Equals(additiveId, "fertilizer", StringComparison.OrdinalIgnoreCase)) { trashId = "supergrow_fertilizer_bottle"; return true; } return false; } private static void EnsureIl2CppBottleTrashPrefabsInjected(TrashManager manager) { if ((Object)(object)manager == (Object)null) { return; } int instanceID = ((Object)manager).GetInstanceID(); if (instanceID != 0 && instanceID == _il2cppTrashPrefabsEnsuredForManagerId) { return; } try { CachePourablePrefab("pgr", "growing/pgr/PGR_Pourable"); CachePourablePrefab("speedgrow", "growing/speedgrow/SpeedGrow_Pourable"); CachePourablePrefab("fertilizer", "growing/fertilizer/Fertilizer_Pourable"); TrashItem baseTrash = manager.GetTrashPrefab("acid"); TrashItem pgrTrash = manager.GetTrashPrefab("pgr"); if ((Object)(object)baseTrash == (Object)null || (Object)(object)((Component)baseTrash).gameObject == (Object)null) { return; } List<TrashItem> additions = new List<TrashItem>(); Ensure("pgr", "supergrow_pgr_bottle"); Ensure("speedgrow", "supergrow_speedgrow_bottle"); Ensure("fertilizer", "supergrow_fertilizer_bottle"); Ensure("supergrow", "supergrow_bottle"); if (additions.Count == 0) { _il2cppTrashPrefabsEnsuredForManagerId = instanceID; return; } Il2CppReferenceArray<TrashItem> trashPrefabs = manager.TrashPrefabs; int num = ((Il2CppArrayBase<TrashItem>)(object)trashPrefabs)?.Length ?? 0; TrashItem[] array = (TrashItem[])(object)new TrashItem[num + additions.Count]; for (int i = 0; i < num; i++) { array[i] = ((Il2CppArrayBase<TrashItem>)(object)trashPrefabs)[i]; } for (int j = 0; j < additions.Count; j++) { array[num + j] = additions[j]; } manager.TrashPrefabs = new Il2CppReferenceArray<TrashItem>(array); _il2cppTrashPrefabsEnsuredForManagerId = instanceID; void Ensure(string additiveId, string newId) { try { if (!((Object)(object)manager.GetTrashPrefab(newId) != (Object)null)) { if (_il2cppBottleTrashPrefabByAdditiveId.TryGetValue(additiveId, out TrashItem value) && (Object)(object)value != (Object)null) { value.ID = newId; additions.Add(value); } else { Transform orCreatePrefabCacheRoot = GetOrCreatePrefabCacheRoot(); GameObject val = ((string.Equals(additiveId, "supergrow", StringComparison.OrdinalIgnoreCase) && (Object)(object)pgrTrash != (Object)null && (Object)(object)((Component)pgrTrash).gameObject != (Object)null) ? ((Component)pgrTrash).gameObject : ((Component)baseTrash).gameObject); GameObject val2 = Object.Instantiate<GameObject>(val); ((Object)val2).name = "SuperGrow_" + additiveId + "_TrashPrefab"; val2.SetActive(val.activeSelf); val2.transform.SetParent(orCreatePrefabCacheRoot, false); Object.DontDestroyOnLoad((Object)(object)val2); TrashItem component = val2.GetComponent<TrashItem>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val2); } else { component.ID = newId; SwapTrashItemVisualsById(additiveId, component); _il2cppBottleTrashPrefabByAdditiveId[additiveId] = component; additions.Add(component); } } } } catch (Exception ex2) { if (!_loggedIl2CppTrashPrefabEnsureException) { _loggedIl2CppTrashPrefabEnsureException = true; MelonLogger.Warning("Failed to create SuperGrow trash prefab for '" + additiveId + "' (IL2CPP): " + ex2.Message); MelonLogger.Warning(ex2.StackTrace ?? "<no stack trace>"); } } } } catch (Exception ex) { if (!_loggedIl2CppTrashPrefabInjectionException) { _loggedIl2CppTrashPrefabInjectionException = true; MelonLogger.Warning("Failed to inject SuperGrow trash prefabs (IL2CPP): " + ex.Message); MelonLogger.Warning(ex.StackTrace ?? "<no stack trace>"); } } } private static void TryAssignIl2CppBottleTrashPrefab(string additiveId, StationItem stationItem) { if ((Object)(object)stationItem == (Object)null || !TryGetBottleTrashId(additiveId, out string trashId)) { return; } try { TrashManager val = Object.FindObjectOfType<TrashManager>(); if ((Object)(object)val == (Object)null) { return; } EnsureIl2CppBottleTrashPrefabsInjected(val); if (_il2cppBottleTrashPrefabByAdditiveId.TryGetValue(additiveId, out TrashItem value) && (Object)(object)value != (Object)null) { stationItem.TrashPrefab = value; return; } TrashItem trashPrefab = val.GetTrashPrefab(trashId); if ((Object)(object)trashPrefab != (Object)null) { stationItem.TrashPrefab = trashPrefab; } } catch { } } private static void DebugLogIl2CppAdditiveTrashIds(string tag) { try { string[] array = new string[3] { "pgr", "speedgrow", "fertilizer" }; foreach (string text in array) { _stationItemPrefabByAdditiveId.TryGetValue(text, out StationItem value); string value2 = (((Object)(object)((value != null) ? value.TrashPrefab : null) != (Object)null) ? value.TrashPrefab.ID : "<null>"); MelonLogger.Msg($"[SuperGrow] IL2CPP additive trash ids ({tag}): {text} -> {value2}"); } } catch { } } private static void ApplyIl2CppBottleTrashPrefabsToCachedStationItems(TrashManager manager) { if ((Object)(object)manager == (Object)null) { return; } try { EnsureIl2CppBottleTrashPrefabsInjected(manager); string[] array = new string[3] { "pgr", "speedgrow", "fertilizer" }; foreach (string text in array) { if (_stationItemPrefabByAdditiveId.TryGetValue(text, out StationItem value) && (Object)(object)value != (Object)null) { TryAssignIl2CppBottleTrashPrefab(text, value); } } } catch { } } public static bool EnsureAdditiveStationItemPrefabs() { if (!TryGetStationItemTemplate(out StationItem templateStationItem)) { return false; } CachePourablePrefab("pgr", "growing/pgr/PGR_Pourable"); CachePourablePrefab("speedgrow", "growing/speedgrow/SpeedGrow_Pourable"); CachePourablePrefab("fertilizer", "growing/fertilizer/Fertilizer_Pourable"); TrashManager val = Object.FindObjectOfType<TrashManager>(); if ((Object)(object)val != (Object)null) { EnsureIl2CppBottleTrashPrefabsInjected(val); } if (!_baseStationItemPrefabsEnsured) { _baseStationItemPrefabsEnsured = true; EnsureStationItemPrefabForAdditive("pgr", templateStationItem, overrideIfPresent: true); EnsureStationItemPrefabForAdditive("speedgrow", templateStationItem, overrideIfPresent: true); EnsureStationItemPrefabForAdditive("fertilizer", templateStationItem, overrideIfPresent: true); } EnsureStationItemPrefabForAdditive("supergrow", templateStationItem, overrideIfPresent: true); return true; } private static void EnsureStationItemPrefabForAdditive(string additiveId, StationItem templateStationItem, bool overrideIfPresent) { ItemDefinition item = Registry.GetItem(additiveId); StorableItemDefinition val = ((item != null) ? ((Il2CppObjectBase)item).TryCast<StorableItemDefinition>() : null); if ((Object)(object)val == (Object)null || (!overrideIfPresent && (Object)(object)val.StationItem != (Object)null)) { return; } if (_stationItemPrefabByAdditiveId.TryGetValue(additiveId, out StationItem value) && (Object)(object)value != (Object)null) { val.StationItem = value; TryAssignIl2CppBottleTrashPrefab(additiveId, value); return; } Transform orCreatePrefabCacheRoot = GetOrCreatePrefabCacheRoot(); GameObject val2 = Object.Instantiate<GameObject>(((Component)templateStationItem).gameObject); ((Object)val2).name = "SuperGrow_StationItemPrefab_" + additiveId; val2.SetActive(true); val2.transform.SetParent(orCreatePrefabCacheRoot, false); Object.DontDestroyOnLoad((Object)(object)val2); StationItem component = val2.GetComponent<StationItem>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val2); return; } TryAssignIl2CppBottleTrashPrefab(additiveId, component); _stationItemPrefabByAdditiveId[additiveId] = component; val.StationItem = component; SwapStationItemVisualsById(additiveId, component); } [HarmonyPatch(typeof(TrashManager), "Start")] [HarmonyPostfix] private static void TrashManager_Start_Postfix_Il2Cpp(TrashManager __instance) { EnsureIl2CppBottleTrashPrefabsInjected(__instance); ApplyIl2CppBottleTrashPrefabsToCachedStationItems(__instance); DebugLogIl2CppAdditiveTrashIds("TrashManager.Start"); } [HarmonyPatch(typeof(ChemistryStationInterface), "Awake")] [HarmonyPrefix] private static void ChemistryStationInterface_Awake_Prefix(ChemistryStationInterface __instance) { try { if ((Object)(object)__instance == (Object)null) { return; } SuperGrowCreator.CreateSuperGrowItem(); if ((Object)(object)_superGrowRecipe == (Object)null) { CreateSuperGrowRecipe(); } if ((Object)(object)_superGrowRecipe == (Object)null) { if (!_loggedRecipeNotReady) { _loggedRecipeNotReady = true; MelonLogger.Warning("SuperGrow recipe is null; cannot add to chemistry station yet"); } return; } List<StationRecipe> recipes = __instance.Recipes; if (recipes == null) { if (!_loggedRecipeNotReady) { _loggedRecipeNotReady = true; MelonLogger.Warning("ChemistryStationInterface.Recipes is null; cannot add SuperGrow recipe"); } } else if (!recipes.Contains(_superGrowRecipe)) { recipes.Add(_superGrowRecipe); MelonLogger.Msg("Added SuperGrow recipe to Chemistry Station"); SetupAdditiveStationItems(); } } catch (Exception ex) { MelonLogger.Error("Failed to add SuperGrow recipe: " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } [HarmonyPatch(typeof(ChemistryStationInterface), "Awake")] [HarmonyPostfix] private static void ChemistryStationInterface_Awake_Postfix(ChemistryStationInterface __instance) { DumpChemistryStationInterfaceStateOnce(__instance, "Awake_Postfix", 1); DumpChemistryStationInterfaceUiStateOnce(__instance, "Awake_Postfix", 4); } [HarmonyPatch(typeof(ChemistryStationInterface), "Open")] [HarmonyPrefix] private static void ChemistryStationInterface_Open_PrefixAudit(ChemistryStationInterface __instance, ChemistryStation station) { DumpChemistryStationInterfaceStateOnce(__instance, "Open_Prefix", 2); DumpChemistryStationInterfaceUiStateOnce(__instance, "Open_Prefix", 8); } [HarmonyPatch(typeof(ChemistryStationInterface), "SetSelectedRecipe")] [HarmonyPrefix] private static void ChemistryStationInterface_SetSelectedRecipe_Prefix(ChemistryStationInterface __instance, StationRecipeEntry entry) { try { StationRecipe val = ((entry != null) ? entry.Recipe : null); string text = SafeGetProductId(val); if (!(text == "<null>") && !(text == "<error>")) { _lastSelectedRecipeProductId = text; _lastSelectedRecipeTitle = SafeGetRecipeEntryTitle(entry); _lastSelectedRecipeId = (((Object)(object)val == (Object)null) ? "<null>" : SafeGetStationRecipeId(val)); _lastSelectedAtTick = Environment.TickCount; } } catch { } } [HarmonyPatch(typeof(ChemistryStationInterface), "BeginTask")] [HarmonyPrefix] private static void ChemistryStationInterface_BeginTask_Prefix(ChemistryStationInterface __instance) { try { if (!((Object)(object)__instance == (Object)null)) { StationRecipeEntry val = TryGetSelectedRecipeEntry(__instance); StationRecipe val2 = ((val != null) ? val.Recipe : null); string text = SafeGetProductId(val2); if (text == "<null>" || text == "<error>") { text = _lastSelectedRecipeProductId ?? text; } if (!(text != "supergrow")) { _superGrowBeginAuditSeq++; _superGrowBeginAuditUntilTick = Environment.TickCount + 10000; _superGrowBeginStation = __instance.ChemistryStation; _superGrowBeginStationSeq = _superGrowBeginAuditSeq; int superGrowBeginAuditSeq = _superGrowBeginAuditSeq; string value = (((Object)(object)val != (Object)null) ? SafeGetRecipeEntryTitle(val) : (_lastSelectedRecipeTitle ?? "<unknown>")); string value2 = (((Object)(object)val2 != (Object)null) ? SafeGetStationRecipeId(val2) : (_lastSelectedRecipeId ?? "<unknown>")); MelonLogger.Msg($"SuperGrow Begin audit #{superGrowBeginAuditSeq}: selectedTitle={value} productId={text} recipeId={value2} beginInteractable={SafeGetBeginInteractable(__instance)}"); BeginTrashAuditWindow(superGrowBeginAuditSeq, __instance.ChemistryStation); BeginBeakerAuditWindow(superGrowBeginAuditSeq, __instance.ChemistryStation); LogRecipeIngredients(val2 ?? GetCachedSelectedRecipe(__instance), superGrowBeginAuditSeq); LogChemistryStationSlotState(_superGrowBeginStation, superGrowBeginAuditSeq, "Begin_Prefix"); } } } catch (Exception ex) { MelonLogger.Error("SuperGrow Begin audit failed (Prefix): " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } [HarmonyPatch(typeof(ChemistryStationInterface), "BeginTask")] [HarmonyPostfix] private static void ChemistryStationInterface_BeginTask_Postfix(ChemistryStationInterface __instance) { try { if (!((Object)(object)__instance == (Object)null) && !TickExpired(_superGrowBeginAuditUntilTick)) { int superGrowBeginAuditSeq = _superGrowBeginAuditSeq; ChemistryStation val = __instance.ChemistryStation; if ((Object)(object)val == (Object)null && _superGrowBeginStationSeq == superGrowBeginAuditSeq) { val = _superGrowBeginStation; } LogChemistryStationSlotState(val, superGrowBeginAuditSeq, "Begin_Postfix"); if ((Object)(object)val != (Object)null) { MelonCoroutines.Start(DelayedChemistryIngredientAudit(superGrowBeginAuditSeq, val)); } } } catch (Exception ex) { MelonLogger.Error("SuperGrow Begin audit failed (Postfix): " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } private static bool TickExpired(int untilTick) { return Environment.TickCount - untilTick >= 0; } private static IEnumerator DelayedChemistryIngredientAudit(int seq, ChemistryStation station) { yield return (object)new WaitForSeconds(0.1f); LogChemistryStationIngredientTransforms(station, seq, "Begin+0.1s"); yield return (object)new WaitForSeconds(0.4f); LogChemistryStationIngredientTransforms(station, seq, "Begin+0.5s"); yield return (object)new WaitForSeconds(0.5f); LogChemistryStationIngredientTransforms(station, seq, "Begin+1.0s"); } private static StationRecipeEntry? TryGetSelectedRecipeEntry(ChemistryStationInterface canvas) { try { Type typeFromHandle = typeof(ChemistryStationInterface); FieldInfo field = typeFromHandle.GetField("selectedRecipe", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object? value = field.GetValue(canvas); return (StationRecipeEntry?)((value is StationRecipeEntry) ? value : null); } PropertyInfo property = typeFromHandle.GetProperty("selectedRecipe", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { object? value2 = property.GetValue(canvas); return (StationRecipeEntry?)((value2 is StationRecipeEntry) ? value2 : null); } FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { if (!(fieldInfo.FieldType != typeof(StationRecipeEntry)) && !(fieldInfo.Name == "RecipeEntryPrefab") && !(fieldInfo.Name == "InProgressRecipeEntry")) { object? value3 = fieldInfo.GetValue(canvas); StationRecipeEntry val = (StationRecipeEntry)((value3 is StationRecipeEntry) ? value3 : null); if ((Object)(object)((val != null) ? val.Recipe : null) != (Object)null) { return val; } } } } catch { } return null; } private static string SafeGetRecipeEntryTitle(StationRecipeEntry? entry) { try { return ((Object)(object)((entry != null) ? entry.TitleLabel : null) == (Object)null) ? "<null>" : (((TMP_Text)entry.TitleLabel).text ?? "<null>"); } catch { return "<error>"; } } private static bool SafeGetBeginInteractable(ChemistryStationInterface canvas) { try { return (Object)(object)canvas.BeginButton != (Object)null && ((Selectable)canvas.BeginButton).interactable; } catch { return false; } } private static string SafeGetProductId(StationRecipe? recipe) { try { object obj; if (recipe == null) { obj = null; } else { ItemQuantity product = recipe.Product; if (product == null) { obj = null; } else { ItemDefinition item = product.Item; obj = ((item != null) ? ((BaseItemDefinition)item).ID : null); } } if (obj == null) { obj = "<null>"; } return (string)obj; } catch { return "<error>"; } } private static string SafeGetStationRecipeId(StationRecipe recipe) { try { return recipe.RecipeID ?? "<null>"; } catch { return "<error>"; } } private static void CreateSuperGrowRecipe() { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Expected O, but got Unknown //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Expected O, but got Unknown //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Expected O, but got Unknown //IL_01de: Unknown result type (might be due to invalid IL or missing references) ItemDefinition item = Registry.GetItem("pgr"); ItemDefinition item2 = Registry.GetItem("speedgrow"); ItemDefinition item3 = Registry.GetItem("fertilizer"); ItemDefinition item4 = Registry.GetItem("supergrow"); if ((Object)(object)item == (Object)null || (Object)(object)item2 == (Object)null || (Object)(object)item3 == (Object)null) { MelonLogger.Error("Could not find one or more base additive definitions"); return; } if ((Object)(object)item4 == (Object)null) { SuperGrowCreator.CreateSuperGrowItem(); item4 = Registry.GetItem("supergrow"); if ((Object)(object)item4 == (Object)null) { MelonLogger.Warning("Could not find SuperGrow definition; will retry when registry is ready"); return; } } _superGrowRecipe = ScriptableObject.CreateInstance<StationRecipe>(); _superGrowRecipe.IsDiscovered = true; _superGrowRecipe.RecipeTitle = "SuperGrow"; _superGrowRecipe.CookTime_Mins = SuperGrowSettings.CookTimeMinutes.Value; _superGrowRecipe.Unlocked = true; List<IngredientQuantity> val = new List<IngredientQuantity>(); IngredientQuantity val2 = new IngredientQuantity(); List<ItemDefinition> val3 = new List<ItemDefinition>(); val3.Add(item); val2.Items = val3; val2.Quantity = SuperGrowSettings.PgrRequired.Value; val.Add(val2); IngredientQuantity val4 = new IngredientQuantity(); List<ItemDefinition> val5 = new List<ItemDefinition>(); val5.Add(item2); val4.Items = val5; val4.Quantity = SuperGrowSettings.SpeedGrowRequired.Value; val.Add(val4); IngredientQuantity val6 = new IngredientQuantity(); List<ItemDefinition> val7 = new List<ItemDefinition>(); val7.Add(item3); val6.Items = val7; val6.Quantity = SuperGrowSettings.FertilizerRequired.Value; val.Add(val6); _superGrowRecipe.Ingredients = val; _superGrowRecipe.Product = new ItemQuantity { Item = item4, Quantity = SuperGrowSettings.OutputQuantity.Value }; _superGrowRecipe.FinalLiquidColor = SuperGrowVisuals.PourColor; } private static bool TryGetStationItemTemplate(out StationItem templateStationItem) { templateStationItem = null; string[] array = new string[4] { "acid", "pgr", "speedgrow", "fertilizer" }; string[] array2 = array; foreach (string text in array2) { ItemDefinition item = Registry.GetItem(text); StorableItemDefinition val = ((item != null) ? ((Il2CppObjectBase)item).TryCast<StorableItemDefinition>() : null); if ((Object)(object)((val != null) ? val.StationItem : null) != (Object)null) { templateStationItem = val.StationItem; return true; } } if (!_loggedMissingStationItemTemplate) { _loggedMissingStationItemTemplate = true; MelonLogger.Warning("Could not find any StationItem template (acid/pgr/speedgrow/fertilizer)"); string[] array3 = array; foreach (string text2 in array3) { ItemDefinition item2 = Registry.GetItem(text2); StorableItemDefinition val2 = ((item2 != null) ? ((Il2CppObjectBase)item2).TryCast<StorableItemDefinition>() : null); MelonLogger.Warning($"{text2}: def={(((Object)(object)val2 == (Object)null) ? "<null>" : ((object)val2).GetType().FullName)} stationItem={(((Object)(object)((val2 != null) ? val2.StationItem : null) == (Object)null) ? "<null>" : ((object)val2.StationItem).GetType().FullName)}"); } } return false; } [HarmonyPatch(typeof(Registry), "Start")] [HarmonyPostfix] private static void Registry_Start_Postfix() { if (_loggedRegistryStart) { return; } _loggedRegistryStart = true; try { SuperGrowCreator.CreateSuperGrowItem(); EnsureAdditiveStationItemPrefabs(); } catch (Exception ex) { MelonLogger.Error("Registry.Start hook failed: " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } public static void SetupAdditiveStationItems() { if (_additivesPatched) { return; } try { CachePourablePrefab("pgr", "growing/pgr/PGR_Pourable"); CachePourablePrefab("speedgrow", "growing/speedgrow/SpeedGrow_Pourable"); CachePourablePrefab("fertilizer", "growing/fertilizer/Fertilizer_Pourable"); if (EnsureAdditiveStationItemPrefabs()) { _additivesPatched = true; MelonLogger.Msg("Set up StationItem on base additives for chemistry station compatibility"); } } catch (Exception ex) { MelonLogger.Error("Failed to set up additive StationItems: " + ex.Message); MelonLogger.Error(ex.StackTrace); } } [HarmonyPatch(typeof(StoredItem), "InitializeStoredItem")] [HarmonyPostfix] private static void StoredItem_InitializeStoredItem_Postfix(StoredItem __instance, StorableItemInstance _item) { try { object obj; if (_item == null) { obj = null; } else { ItemDefinition definition = ((ItemInstance)_item).Definition; obj = ((definition != null) ? ((BaseItemDefinition)definition).ID : null); } string text = (string)obj; if (!(text != "supergrow")) { ApplySuperGrowMaterialsToRenderers(Il2CppArrayBase<Renderer>.op_Implicit(((Component)__instance).GetComponentsInChildren<Renderer>(true))); } } catch (Exception ex) { MelonLogger.Error("Failed to apply SuperGrow visuals to stored item: " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } private static void SetPendingStationTrashReskins(List<PendingTrashReskin> reskins) { _pendingStationTrashReskins.Clear(); if (reskins.Count > 0) { _pendingStationTrashReskins.AddRange(reskins); _pendingStationTrashReskinExpireTick = Environment.TickCount + 5000; } else { _pendingStationTrashReskinExpireTick = 0; } } [HarmonyPatch(typeof(ChemistryStation), "CreateTrash")] [HarmonyPrefix] private static void ChemistryStation_CreateTrash_Prefix(ChemistryStation __instance, List<StationItem> mixerItems) { try { if (mixerItems == null) { return; } List<PendingTrashReskin> list = new List<PendingTrashReskin>(); for (int i = 0; i < mixerItems.Count; i++) { StationItem val = mixerItems[i]; if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null) { continue; } string text = TryParseAdditiveIdFromStationItemName(((Object)((Component)val).gameObject).name); if (text != null) { string text2 = (((Object)(object)val.TrashPrefab != (Object)null) ? val.TrashPrefab.ID : null); if (!string.IsNullOrEmpty(text2)) { list.Add(new PendingTrashReskin(text2, text)); } } } SetPendingStationTrashReskins(list); } catch { } } private static string? TryParseAdditiveIdFromStationItemName(string? stationItemName) { if (string.IsNullOrEmpty(stationItemName)) { return null; } int num = stationItemName.IndexOf("SuperGrow_StationItemPrefab_", StringComparison.OrdinalIgnoreCase); if (num < 0) { return null; } num += "SuperGrow_StationItemPrefab_".Length; if (num >= stationItemName.Length) { return null; } int num2 = stationItemName.IndexOf('(', num); if (num2 < 0) { num2 = stationItemName.Length; } string text = stationItemName.Substring(num, num2 - num).Trim(); if (text.Length == 0) { return null; } text = text.ToLowerInvariant(); object result; switch (text) { default: result = null; break; case "pgr": case "speedgrow": case "fertilizer": case "supergrow": result = text; break; } return (string?)result; } [HarmonyPatch(typeof(TrashItem), "Start")] [HarmonyPostfix] private static void TrashItem_Start_Postfix(TrashItem __instance) { try { if (_pendingStationTrashReskins.Count == 0) { return; } if (_pendingStationTrashReskinExpireTick != 0 && Environment.TickCount - _pendingStationTrashReskinExpireTick >= 0) { _pendingStationTrashReskins.Clear(); _pendingStationTrashReskinExpireTick = 0; return; } string iD = __instance.ID; if (string.IsNullOrEmpty(iD)) { return; } for (int i = 0; i < _pendingStationTrashReskins.Count; i++) { PendingTrashReskin pendingTrashReskin = _pendingStationTrashReskins[i]; if (!(pendingTrashReskin.TrashId != iD)) { _pendingStationTrashReskins.RemoveAt(i); SwapTrashItemVisualsById(pendingTrashReskin.AdditiveId, __instance); break; } } } catch (Exception ex) { MelonLogger.Error("Failed to apply SuperGrow visuals to trash item: " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } private static bool IsChemistryBeakerFillable(Fillable fillable) { if ((Object)(object)fillable == (Object)null) { return false; } LiquidContainer liquidContainer = fillable.LiquidContainer; if ((Object)(object)liquidContainer == (Object)null || (Object)(object)((Component)liquidContainer).transform == (Object)null) { return false; } Transform transform = ((Component)liquidContainer).transform; if (!string.Equals(((Object)transform).name, "Liquid", StringComparison.OrdinalIgnoreCase)) { return false; } Transform parent = transform.parent; if ((Object)(object)parent == (Object)null || !string.Equals(((Object)parent).name, "Beaker", StringComparison.OrdinalIgnoreCase)) { return false; } Transform parent2 = parent.parent; if ((Object)(object)parent2 == (Object)null || !((Object)parent2).name.StartsWith("Beaker", StringComparison.OrdinalIgnoreCase)) { return false; } Transform val = parent2; while ((Object)(object)val != (Object)null) { if (((Object)val).name != null && ((Object)val).name.IndexOf("ChemistryStation", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } val = val.parent; } return false; } private static void CachePourablePrefab(string additiveId, string pourablePath) { if (!_pourablePrefabs.ContainsKey(additiveId)) { GameObject val = Resources.Load<GameObject>(pourablePath); if ((Object)(object)val != (Object)null) { _pourablePrefabs[additiveId] = val; MelonLogger.Msg("Cached pourable prefab for " + additiveId); } else { MelonLogger.Warning("Could not load pourable prefab for " + additiveId + " at " + pourablePath); } } } private static Transform? FindStationItemBottleContainer(StationItem stationItem) { Transform val = ((Component)stationItem).transform.Find("Pourable"); if ((Object)(object)val == (Object)null) { return null; } Transform result = null; int childCount = val.childCount; for (int i = 0; i < childCount; i++) { Transform child = val.GetChild(i); if ((Object)(object)child != (Object)null && ((Object)child).name.IndexOf("Bottle", StringComparison.OrdinalIgnoreCase) >= 0) { result = child; break; } } return result; } private static void SwapBottleMeshesAndMaterials(GameObject templatePrefab, Transform targetRoot) { Il2CppArrayBase<MeshFilter> componentsInChildren = templatePrefab.GetComponentsInChildren<MeshFilter>(true); Il2CppArrayBase<MeshFilter> componentsInChildren2 = ((Component)targetRoot).GetComponentsInChildren<MeshFilter>(true); foreach (MeshFilter item in componentsInChildren2) { if ((Object)(object)item == (Object)null) { continue; } string text = ((Object)item).name.ToLowerInvariant(); foreach (MeshFilter item2 in componentsInChildren) { if ((Object)(object)item2 == (Object)null) { continue; } string text2 = ((Object)item2).name.ToLowerInvariant(); if ((!text.Contains("body") || !text2.Contains("body")) && (!text.Contains("label") || !text2.Contains("label")) && (!text.Contains("lid") || !text2.Contains("lid"))) { continue; } item.sharedMesh = item2.sharedMesh; MeshRenderer component = ((Component)item).GetComponent<MeshRenderer>(); MeshRenderer component2 = ((Component)item2).GetComponent<MeshRenderer>(); if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null) { ((Renderer)component).sharedMaterials = ((Renderer)component2).sharedMaterials; } break; } } } private static void ApplySuperGrowMaterialsToRenderers(Renderer[]? renderers) { SuperGrowVisuals.ApplySuperGrowMaterialsToRenderers(renderers); } private static void SetupAdditiveStationItem(string additiveId, StationItem templateStationItem) { ItemDefinition item = Registry.GetItem(additiveId); StorableItemDefinition val = ((item != null) ? ((Il2CppObjectBase)item).TryCast<StorableItemDefinition>() : null); if ((Object)(object)val == (Object)null) { MelonLogger.Warning("Could not find additive: " + additiveId); } else if (!((Object)(object)val.StationItem != (Object)null)) { val.StationItem = templateStationItem; } } private static void SwapTrashItemVisualsById(string id, TrashItem trashItem) { if ((Object)(object)trashItem == (Object)null || string.IsNullOrEmpty(id)) { return; } bool flag = id == "supergrow"; if (!flag && id != "pgr" && id != "speedgrow" && id != "fertilizer") { return; } GameObject value = null; if (flag) { _pourablePrefabs.TryGetValue("pgr", out value); } else { _pourablePrefabs.TryGetValue(id, out value); } if ((Object)(object)value == (Object)null) { return; } try { if (!((Object)(object)((Component)trashItem).transform == (Object)null)) { SwapBottleMeshesAndMaterials(value, ((Component)trashItem).transform); if (flag) { ApplySuperGrowMaterialsToRenderers(Il2CppArrayBase<Renderer>.op_Implicit(((Component)trashItem).GetComponentsInChildren<Renderer>(true))); } } } catch (Exception ex) { MelonLogger.Error("Failed to swap trash visuals for " + id + ": " + ex.Message); MelonLogger.Error(ex.StackTrace); } } private static void SwapStationItemVisualsById(string id, StationItem stationItem) { //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)stationItem == (Object)null || string.IsNullOrEmpty(id)) { return; } bool flag = id == "supergrow"; if (!flag && id != "pgr" && id != "speedgrow" && id != "fertilizer") { return; } GameObject value = null; if (flag) { _pourablePrefabs.TryGetValue("pgr", out value); } else { _pourablePrefabs.TryGetValue(id, out value); } if ((Object)(object)value == (Object)null) { return; } try { Transform val = FindStationItemBottleContainer(stationItem); if ((Object)(object)val == (Object)null) { return; } SwapBottleMeshesAndMaterials(value, val); if (flag) { ApplySuperGrowMaterialsToRenderers(Il2CppArrayBase<Renderer>.op_Implicit(((Component)val).GetComponentsInChildren<Renderer>(true))); } object obj; if (!((Object)(object)((Component)stationItem).transform != (Object)null)) { obj = null; } else { Transform obj2 = ((Component)stationItem).transform.Find("Pourable"); obj = ((obj2 != null) ? ((Component)obj2).GetComponent<PourableModule>() : null); } PourableModule val2 = (PourableModule)obj; if ((Object)(object)val2 != (Object)null && (Object)(object)val2.LiquidContainer != (Object)null) { LiquidContainer liquidContainer = val2.LiquidContainer; if ((Object)(object)liquidContainer.LiquidVolume != (Object)null) { Transform transform = ((Component)liquidContainer.LiquidVolume).transform; transform.localScale *= 0.65f; } liquidContainer.MaxLevel *= 0.65f; if (_additiveColors.TryGetValue(id, out var value2)) { val2.LiquidType = id; val2.LiquidColor = value2; val2.PourParticlesColor = value2; } } } catch (Exception ex) { MelonLogger.Error("Failed to swap station item visuals for " + id + ": " + ex.Message); MelonLogger.Error(ex.StackTrace); } } private static void SwapStationItemVisualsById(string id, StationItem stationItem, StorableItemDefinition itemDef) { if (!((Object)(object)stationItem == (Object)null) && !((Object)(object)itemDef == (Object)null)) { SwapStationItemVisualsById(id, stationItem); } } } [HarmonyPatch] internal static class GrowContainerPatches { private static readonly string[] SuperGrowSupersededAdditiveIds = new string[3] { "pgr", "speedgrow", "fertilizer" }; private const string SuperGrowBottleTrashId = "supergrow_bottle"; private static bool _loggedGrowContainerTrashPrefabAssignException; private static readonly Vector3 HiddenPrefabPosition = new Vector3(100000f, 100000f, 100000f); private static Pourable? _superGrowPourablePrefab; private const int MaxTaskLogs = 50; private const int MaxTrashLogs = 200; private const int TrashLogWindowSize = 40; private
SuperGrow_Mono.dll
Decompiled 15 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using HarmonyLib; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using ScheduleOne; using ScheduleOne.Core.Items.Framework; using ScheduleOne.DevUtilities; using ScheduleOne.Equipping; using ScheduleOne.Growing; using ScheduleOne.ItemFramework; using ScheduleOne.ObjectScripts; using ScheduleOne.PlayerScripts; using ScheduleOne.PlayerTasks; using ScheduleOne.PlayerTasks.Tasks; using ScheduleOne.StationFramework; using ScheduleOne.Storage; using ScheduleOne.Trash; using ScheduleOne.UI.Stations; using SuperGrow; using SuperGrow.Features; using SuperGrow.Patches; using SuperGrow.Utils; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Core), "SuperGrow", "1.3.4", "HazDS", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SuperGrow")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+22bbaa0cd7f8c88418ee8cc3f9785971198326d8")] [assembly: AssemblyProduct("SuperGrow")] [assembly: AssemblyTitle("SuperGrow")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.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] [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] [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 SuperGrow { internal static class SuperGrowSettings { private static bool _initialized; private static MelonPreferences_Category? _prefsCategory; public static MelonPreferences_Entry<int> PgrRequired { get; private set; } public static MelonPreferences_Entry<int> SpeedGrowRequired { get; private set; } public static MelonPreferences_Entry<int> FertilizerRequired { get; private set; } public static MelonPreferences_Entry<int> OutputQuantity { get; private set; } public static MelonPreferences_Entry<int> CookTimeMinutes { get; private set; } public static MelonPreferences_Entry<float> YieldMultiplier { get; private set; } public static MelonPreferences_Entry<float> InstantGrowth { get; private set; } public static MelonPreferences_Entry<float> QualityChange { get; private set; } public static void Initialize() { if (!_initialized) { _prefsCategory = MelonPreferences.CreateCategory("SuperGrow", "SuperGrow Settings"); PgrRequired = _prefsCategory.CreateEntry<int>("PgrRequired", 1, "PGR Required", "Amount of PGR needed per craft", false, false, (ValueValidator)null, (string)null); SpeedGrowRequired = _prefsCategory.CreateEntry<int>("SpeedGrowRequired", 1, "Speed Grow Required", "Amount of Speed Grow needed per craft", false, false, (ValueValidator)null, (string)null); FertilizerRequired = _prefsCategory.CreateEntry<int>("FertilizerRequired", 1, "Fertilizer Required", "Amount of Fertilizer needed per craft", false, false, (ValueValidator)null, (string)null); OutputQuantity = _prefsCategory.CreateEntry<int>("OutputQuantity", 3, "Output Quantity", "Amount of SuperGrow produced per craft", false, false, (ValueValidator)null, (string)null); CookTimeMinutes = _prefsCategory.CreateEntry<int>("CookTimeMinutes", 30, "Cook Time (Minutes)", "Chemistry Station cook time in in-game minutes", false, false, (ValueValidator)null, (string)null); YieldMultiplier = _prefsCategory.CreateEntry<float>("YieldMultiplier", 1.5f, "Yield Multiplier", "Yield multiplier applied to plants (1.5 = 50% more yield)", false, false, (ValueValidator)null, (string)null); InstantGrowth = _prefsCategory.CreateEntry<float>("InstantGrowth", 0.5f, "Instant Growth", "Instant growth progress (0.5 = 50% instant growth)", false, false, (ValueValidator)null, (string)null); QualityChange = _prefsCategory.CreateEntry<float>("QualityChange", 1f, "Quality Change", "Quality modifier applied to plants", false, false, (ValueValidator)null, (string)null); Clamp(PgrRequired, 1, 10); Clamp(SpeedGrowRequired, 1, 10); Clamp(FertilizerRequired, 1, 10); Clamp(OutputQuantity, 1, 10); Clamp(CookTimeMinutes, 1, 240); Clamp(YieldMultiplier, 0.1f, 10f); Clamp(InstantGrowth, 0f, 1f); Clamp(QualityChange, -1f, 1f); _initialized = true; } } private static void Clamp(MelonPreferences_Entry<int> entry, int min, int max) { if (entry.Value < min) { entry.Value = min; } if (entry.Value > max) { entry.Value = max; } } private static void Clamp(MelonPreferences_Entry<float> entry, float min, float max) { if (entry.Value < min) { entry.Value = min; } if (entry.Value > max) { entry.Value = max; } } } public class Core : MelonMod { private bool _itemsInitialized; private int _nextInitAttemptTick; private const int InitAttemptIntervalMs = 250; public static Core Instance { get; private set; } public override void OnInitializeMelon() { Instance = this; SuperGrowSettings.Initialize(); MelonLogger.Msg("[SuperGrow v1.3.4] Initialized."); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (sceneName == "Menu") { _itemsInitialized = false; _nextInitAttemptTick = 0; ChemistryStationPatches.Reset(); } } public override void OnUpdate() { ChemistryStationPatches.DumpStationItemInitializePatchesOnce("OnUpdate"); if (_itemsInitialized && (Object)(object)Registry.GetItem("supergrow") != (Object)null) { return; } if ((Object)(object)Registry.GetItem("supergrow") != (Object)null) { _itemsInitialized = true; } else if (ShouldAttemptInitNow()) { _itemsInitialized = false; if (SuperGrowWorldState.IsRegistryReady()) { SuperGrowCreator.CreateSuperGrowItem(); _itemsInitialized = (Object)(object)Registry.GetItem("supergrow") != (Object)null; } } } private bool ShouldAttemptInitNow() { int tickCount = Environment.TickCount; if (tickCount - _nextInitAttemptTick < 0) { return false; } _nextInitAttemptTick = tickCount + 250; return true; } } internal static class SuperGrowAssets { private const string IconResourceName = "SuperGrow.Assets.SuperGrow_Icon.png"; private const string LabelResourceName = "SuperGrow.Assets.SuperGrow_Label.png"; private static Sprite? _icon; private static Texture2D? _labelTexture; private static bool _loggedIconLoadException; private static bool _loggedLabelLoadException; private static bool _loggedImageLoadException; public static Sprite? GetIconSprite() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_icon != (Object)null) { return _icon; } try { byte[] array = LoadEmbeddedResourceBytes("SuperGrow.Assets.SuperGrow_Icon.png"); if (array == null) { return null; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!TryLoadImage(val, array)) { MelonLogger.Warning("Failed to decode SuperGrow.Assets.SuperGrow_Icon.png"); return null; } ((Object)val).name = "SuperGrow_Icon"; _icon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); return _icon; } catch (Exception ex) { if (!_loggedIconLoadException) { _loggedIconLoadException = true; MelonLogger.Warning("Failed to load icon: " + ex.Message); MelonLogger.Warning(ex.StackTrace ?? "<no stack trace>"); } return null; } } public static Texture2D? GetLabelTexture() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown if ((Object)(object)_labelTexture != (Object)null) { return _labelTexture; } try { byte[] array = LoadEmbeddedResourceBytes("SuperGrow.Assets.SuperGrow_Label.png"); if (array == null) { return null; } _labelTexture = new Texture2D(2, 2, (TextureFormat)4, false); if (!TryLoadImage(_labelTexture, array)) { MelonLogger.Warning("Failed to decode SuperGrow.Assets.SuperGrow_Label.png"); _labelTexture = null; return null; } ((Object)_labelTexture).name = "SuperGrow_Label"; return _labelTexture; } catch (Exception ex) { if (!_loggedLabelLoadException) { _loggedLabelLoadException = true; MelonLogger.Error("Failed to load SuperGrow label texture: " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } _labelTexture = null; return null; } } private static byte[]? LoadEmbeddedResourceBytes(string resourceName) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); using Stream stream = executingAssembly.GetManifestResourceStream(resourceName); if (stream == null) { MelonLogger.Warning("Could not find embedded resource: " + resourceName); return null; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); return memoryStream.ToArray(); } private static bool TryLoadImage(Texture2D texture, byte[] bytes) { try { Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule") ?? typeof(Texture2D).Assembly.GetType("UnityEngine.ImageConversion"); if (type == null) { return false; } MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public); MethodInfo[] array = methods; bool flag = default(bool); foreach (MethodInfo methodInfo in array) { if (methodInfo.Name != "LoadImage") { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if ((parameters.Length != 2 && parameters.Length != 3) || parameters[0].ParameterType != typeof(Texture2D)) { continue; } Type parameterType = parameters[1].ParameterType; if (parameterType == typeof(byte[])) { object obj = ((parameters.Length != 3) ? methodInfo.Invoke(null, new object[2] { texture, bytes }) : methodInfo.Invoke(null, new object[3] { texture, bytes, false })); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } } return false; } catch (Exception ex) { if (!_loggedImageLoadException) { _loggedImageLoadException = true; MelonLogger.Warning("Failed to decode embedded image bytes via ImageConversion.LoadImage: " + ex.Message); MelonLogger.Warning(ex.StackTrace ?? "<no stack trace>"); } return false; } } } internal static class SuperGrowWorldState { private static bool _loggedReady; private static bool _ready; private static bool _loggedRegistryReadyException; public static bool IsRegistryReady() { try { if (_ready) { return true; } ItemDefinition item = Registry.GetItem("pgr"); AdditiveDefinition val = (AdditiveDefinition)(object)((item is AdditiveDefinition) ? item : null); ItemDefinition item2 = Registry.GetItem("speedgrow"); AdditiveDefinition val2 = (AdditiveDefinition)(object)((item2 is AdditiveDefinition) ? item2 : null); ItemDefinition item3 = Registry.GetItem("fertilizer"); AdditiveDefinition val3 = (AdditiveDefinition)(object)((item3 is AdditiveDefinition) ? item3 : null); if ((Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null && (Object)(object)val3 == (Object)null) { return false; } _ready = true; if (!_loggedReady) { _loggedReady = true; MelonLogger.Msg("Registry appears ready; initializing item."); } return true; } catch (Exception ex) { if (!_loggedRegistryReadyException) { _loggedRegistryReadyException = true; MelonLogger.Warning("Registry readiness check failed: " + ex.Message); MelonLogger.Warning(ex.StackTrace ?? "<no stack trace>"); } return false; } } } } namespace SuperGrow.Utils { public static class Constants { public static class Game { public const string GAME_STUDIO = "TVGS"; public const string GAME_NAME = "Schedule I"; } public static class Additives { public const string PGR = "pgr"; public const string SPEED_GROW = "speedgrow"; public const string FERTILIZER = "fertilizer"; } public static class ItemIds { public const string SUPER_GROW = "supergrow"; } public static class DefaultEffects { public const float YIELD_MULTIPLIER = 1.5f; public const float INSTANT_GROWTH = 0.5f; public const float QUALITY_CHANGE = 1f; } public const string MOD_NAME = "SuperGrow"; public const string MOD_VERSION = "1.3.4"; public const string MOD_AUTHOR = "HazDS"; public const string PREFERENCES_CATEGORY = "SuperGrow"; } internal static class SuperGrowVisuals { internal static readonly Color PourColor = new Color(0.4f, 0.2f, 0.6f, 1f); internal static readonly Color LidTint = new Color(0.6f, 0.4f, 0.8f, 1f); internal static void ApplySuperGrowMaterialsToRenderers(Renderer[]? renderers) { //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) if (renderers == null) { return; } Texture2D labelTexture = SuperGrowAssets.GetLabelTexture(); if ((Object)(object)labelTexture == (Object)null) { MelonLogger.Warning("SuperGrow label texture is null, cannot apply"); return; } try { foreach (Renderer val in renderers) { if ((Object)(object)val == (Object)null) { continue; } string text = ((Object)val).name.ToLowerInvariant(); bool flag = text.Contains("label"); if (!flag) { Material[] sharedMaterials = val.sharedMaterials; foreach (Material val2 in sharedMaterials) { if ((Object)(object)val2 != (Object)null && ((Object)val2).name.ToLowerInvariant().Contains("label")) { flag = true; break; } } } bool flag2 = text.Contains("lid"); if (!flag2) { Material[] sharedMaterials2 = val.sharedMaterials; foreach (Material val3 in sharedMaterials2) { if ((Object)(object)val3 != (Object)null && ((Object)val3).name.ToLowerInvariant().Contains("lid")) { flag2 = true; break; } } } if (flag) { Material[] materials = val.materials; foreach (Material val4 in materials) { if (!((Object)(object)val4 == (Object)null)) { val4.mainTexture = (Texture)(object)labelTexture; if (val4.HasProperty("_BaseMap")) { val4.SetTexture("_BaseMap", (Texture)(object)labelTexture); } if (val4.HasProperty("_MainTex")) { val4.SetTexture("_MainTex", (Texture)(object)labelTexture); } } } val.materials = materials; } else { if (!flag2) { continue; } Material[] materials2 = val.materials; foreach (Material val5 in materials2) { if (!((Object)(object)val5 == (Object)null)) { val5.color = LidTint; if (val5.HasProperty("_BaseColor")) { val5.SetColor("_BaseColor", LidTint); } if (val5.HasProperty("_Color")) { val5.SetColor("_Color", LidTint); } } } val.materials = materials2; } } } catch (Exception ex) { MelonLogger.Error("Failed to apply SuperGrow materials: " + ex.Message); MelonLogger.Error(ex.StackTrace); } } } } namespace SuperGrow.Patches { [HarmonyPatch] internal static class ChemistryStationPatches { private readonly struct PendingTrashReskin { public string TrashId { get; } public string AdditiveId { get; } public PendingTrashReskin(string trashId, string additiveId) { TrashId = trashId; AdditiveId = additiveId; } } private static StationRecipe? _superGrowRecipe; private static bool _additivesPatched; private static bool _loggedMissingStationItemTemplate; private static bool _loggedRegistryStart; private static bool _loggedRecipeNotReady; private static int _superGrowBeginAuditUntilTick; private static int _superGrowBeginAuditSeq; private static ChemistryStation? _superGrowBeginStation; private static int _superGrowBeginStationSeq; private static string? _lastSelectedRecipeProductId; private static string? _lastSelectedRecipeTitle; private static string? _lastSelectedRecipeId; private static int _lastSelectedAtTick; private static bool _stationItemInitializePatchInfoDumped; private static readonly Dictionary<int, int> _chemCanvasDumpMaskByInstanceId = new Dictionary<int, int>(); private const int TrashAuditWindowMs = 60000; private const int TrashAuditMaxLogs = 50; private static int _trashAuditUntilTick; private static int _trashAuditSeq; private static int _trashAuditTrashManagerLogged; private static int _trashAuditGetTrashPrefabLogged; private static int _trashAuditTrashItemStartLogged; private static bool _trashAuditHasStationPos; private static Vector3 _trashAuditStationPos; private static readonly HashSet<string> _trashAuditSeenTrashIds = new HashSet<string>(); private static readonly HashSet<string> _trashAuditSeenGetTrashPrefabIds = new HashSet<string>(); private static bool _trashAuditTrashPrefabsDumped; private static TrashManager? _trashAuditManager; private const int BeakerAuditWindowMs = 30000; private const int BeakerAuditMaxLogs = 80; private const float BeakerAuditMinLoggedLevelDelta = 0.05f; private const float BeakerAuditLevelEdgeEpsilon = 0.01f; private const float BeakerAuditMinLoggedColorDelta = 0.02f; private const int BeakerContentsAuditMaxLogs = 120; private const int BeakerContentsAuditMinIntervalMs = 250; private const float BeakerContentsAuditMinTotalDelta = 0.02f; private static int _beakerAuditUntilTick; private static int _beakerAuditSeq; private static int _beakerAuditLiquidColorLogged; private static int _beakerAuditLiquidLevelLogged; private static int _beakerContentsAuditLogged; private static bool _beakerAuditHasStationPos; private static Vector3 _beakerAuditStationPos; private static readonly HashSet<int> _beakerAuditSeenContainerIds = new HashSet<int>(); private static readonly HashSet<int> _beakerAuditTrackedContainerIds = new HashSet<int>(); private static readonly Dictionary<int, float> _beakerAuditLastLoggedLevel = new Dictionary<int, float>(); private static readonly Dictionary<int, Color> _beakerAuditLastLoggedColor = new Dictionary<int, Color>(); private static readonly Dictionary<int, int> _beakerContentsAuditLastTickByFillableId = new Dictionary<int, int>(); private static readonly Dictionary<int, float> _beakerContentsAuditLastTotalByFillableId = new Dictionary<int, float>(); private static readonly Dictionary<int, string> _beakerContentsAuditLastLabelByFillableId = new Dictionary<int, string>(); private static bool _beakerAuditExpiredLogged; private const int ChemCanvasDump_AwakePostfix = 1; private const int ChemCanvasDump_OpenPrefix = 2; private const int ChemCanvasDump_UiAwakePostfix = 4; private const int ChemCanvasDump_UiOpenPrefix = 8; private const string PgrBottleTrashId = "supergrow_pgr_bottle"; private const string SpeedGrowBottleTrashId = "supergrow_speedgrow_bottle"; private const string FertilizerBottleTrashId = "supergrow_fertilizer_bottle"; private const string SuperGrowBottleTrashId = "supergrow_bottle"; private static bool _monoTrashPrefabsInjected; private static readonly Dictionary<string, TrashItem> _monoBottleTrashPrefabByAdditiveId = new Dictionary<string, TrashItem>(); private static bool _loggedMonoTrashPrefabInjectionException; private static int _pendingStationTrashReskinExpireTick; private static readonly List<PendingTrashReskin> _pendingStationTrashReskins = new List<PendingTrashReskin>(); private static readonly Dictionary<string, GameObject> _pourablePrefabs = new Dictionary<string, GameObject>(); private static readonly Dictionary<string, Color> _additiveColors = new Dictionary<string, Color> { { "pgr", new Color(1f, 0.506f, 0.506f, 1f) }, { "speedgrow", new Color(0.506f, 0.812f, 1f, 1f) }, { "fertilizer", new Color(0.639f, 1f, 0.506f, 1f) }, { "supergrow", SuperGrowVisuals.PourColor } }; private const float LiquidScale = 0.65f; public static void Reset() { _superGrowRecipe = null; _additivesPatched = false; _loggedMissingStationItemTemplate = false; _loggedRegistryStart = false; _loggedRecipeNotReady = false; _chemCanvasDumpMaskByInstanceId.Clear(); } private static void BeginBeakerAuditWindow(int seq, ChemistryStation? station) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) _beakerAuditSeq = seq; _beakerAuditUntilTick = Environment.TickCount + 30000; _beakerAuditLiquidColorLogged = 0; _beakerAuditLiquidLevelLogged = 0; _beakerContentsAuditLogged = 0; _beakerAuditSeenContainerIds.Clear(); _beakerAuditTrackedContainerIds.Clear(); _beakerAuditLastLoggedLevel.Clear(); _beakerAuditLastLoggedColor.Clear(); _beakerContentsAuditLastTickByFillableId.Clear(); _beakerContentsAuditLastTotalByFillableId.Clear(); _beakerContentsAuditLastLabelByFillableId.Clear(); _beakerAuditExpiredLogged = false; if ((Object)(object)station != (Object)null && (Object)(object)((Component)station).transform != (Object)null) { _beakerAuditHasStationPos = true; _beakerAuditStationPos = ((Component)station).transform.position; } else { _beakerAuditHasStationPos = false; _beakerAuditStationPos = Vector3.zero; } string arg = (_beakerAuditHasStationPos ? ((object)Unsafe.As<Vector3, Vector3>(ref _beakerAuditStationPos)/*cast due to .constrained prefix*/).ToString() : "<unknown>"); MelonLogger.Msg($"SuperGrow beaker audit #{seq}: enabled for {30000}ms stationPos={arg}"); try { if ((Object)(object)station != (Object)null) { DumpNearbyLiquidContainersOnce(station, "BeginBeakerAuditWindow"); } } catch { } } private static bool IsBeakerAuditActive() { if (_beakerAuditUntilTick == 0) { return false; } if (Environment.TickCount - _beakerAuditUntilTick < 0) { return true; } if (!_beakerAuditExpiredLogged) { _beakerAuditExpiredLogged = true; try { MelonLogger.Msg($"SuperGrow beaker audit #{_beakerAuditSeq}: expired (levelLogs={_beakerAuditLiquidLevelLogged}/{80} colorLogs={_beakerAuditLiquidColorLogged}/{80} trackedIds={_beakerAuditTrackedContainerIds.Count})"); } catch { } } _beakerAuditUntilTick = 0; return false; } private static bool IsNearBeakerAuditedStation(Vector3 position) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (!_beakerAuditHasStationPos) { return true; } return Vector3.Distance(position, _beakerAuditStationPos) <= 35f; } private static string GetTransformPath(Transform? transform) { if ((Object)(object)transform == (Object)null) { return "<null>"; } StringBuilder stringBuilder = new StringBuilder(); Transform val = transform; while ((Object)(object)val != (Object)null) { stringBuilder.Insert(0, "/" + ((Object)val).name); val = val.parent; } return (stringBuilder.Length == 0) ? "<empty>" : stringBuilder.ToString(); } private static bool ShouldTrackLiquidContainer(string goName, string path) { if (goName == "Liquid" && path.Contains("/Beaker(") && path.EndsWith("/Beaker/Liquid")) { return true; } if (goName == "Pourable" && path.EndsWith("/Pourable") && path.Contains("/ItemContainer/")) { return true; } return false; } private static bool ColorsApproximatelyEqual(Color a, Color b) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) return Mathf.Abs(a.r - b.r) < 0.02f && Mathf.Abs(a.g - b.g) < 0.02f && Mathf.Abs(a.b - b.b) < 0.02f && Mathf.Abs(a.a - b.a) < 0.02f; } private static void DumpNearbyLiquidContainersOnce(ChemistryStation station, string reason) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) try { LiquidContainer[] componentsInChildren = ((Component)station).GetComponentsInChildren<LiquidContainer>(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { MelonLogger.Msg($"SuperGrow beaker audit #{_beakerAuditSeq}: no LiquidContainers found ({reason})"); return; } MelonLogger.Msg($"SuperGrow beaker audit #{_beakerAuditSeq}: LiquidContainers near station ({reason}) count={componentsInChildren.Length}"); int num = 0; for (int i = 0; i < componentsInChildren.Length; i++) { if (num >= 25) { break; } LiquidContainer val = componentsInChildren[i]; if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || (Object)(object)((Component)val).transform == (Object)null) { continue; } Vector3 position = ((Component)val).transform.position; if (IsNearBeakerAuditedStation(position)) { int instanceID = ((Object)val).GetInstanceID(); string text = ((Object)((Component)val).gameObject).name ?? "<unnamed>"; string transformPath = GetTransformPath(((Component)val).transform); string text2 = (_beakerAuditHasStationPos ? Vector3.Distance(position, _beakerAuditStationPos).ToString("0.0") : "<n/a>"); MelonLogger.Msg($" - containerId={instanceID} name={text} dist={text2} level={val.CurrentLiquidLevel:0.###}/{val.MaxLevel:0.###} color=({val.LiquidColor.r:0.###},{val.LiquidColor.g:0.###},{val.LiquidColor.b:0.###},{val.LiquidColor.a:0.###}) path={transformPath}"); if (ShouldTrackLiquidContainer(text, transformPath)) { _beakerAuditTrackedContainerIds.Add(instanceID); } num++; } } } catch (Exception ex) { MelonLogger.Error("SuperGrow beaker audit: failed to dump LiquidContainers (" + reason + "): " + ex.Message); } } [HarmonyPatch(typeof(Fillable), "ResetContents")] [HarmonyPostfix] private static void Fillable_ResetContents_DebugPostfix(Fillable __instance) { if (!IsBeakerAuditActive() || _beakerContentsAuditLogged >= 120) { return; } try { if (!((Object)(object)__instance == (Object)null) && IsChemistryBeakerFillable(__instance)) { int instanceID = ((Object)__instance).GetInstanceID(); _beakerContentsAuditLastTickByFillableId.Remove(instanceID); _beakerContentsAuditLastTotalByFillableId.Remove(instanceID); _beakerContentsAuditLastLabelByFillableId.Remove(instanceID); _beakerContentsAuditLogged++; MelonLogger.Msg($"SuperGrow beaker audit #{_beakerAuditSeq}: Fillable.ResetContents fillableId={instanceID}"); } } catch (Exception ex) { MelonLogger.Error("SuperGrow beaker audit: Fillable.ResetContents logging failed: " + ex.Message); } } [HarmonyPatch(typeof(Fillable), "AddLiquid", new Type[] { typeof(string), typeof(float), typeof(Color) })] [HarmonyPostfix] private static void Fillable_AddLiquid_DebugPostfix(Fillable __instance, string label, float volume, Color color) { //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) if (!IsBeakerAuditActive() || _beakerContentsAuditLogged >= 120) { return; } try { if (!((Object)(object)__instance == (Object)null) && IsChemistryBeakerFillable(__instance)) { int instanceID = ((Object)__instance).GetInstanceID(); int tickCount = Environment.TickCount; float totalLiquidVolume = __instance.GetTotalLiquidVolume(); int value; bool flag = _beakerContentsAuditLastTickByFillableId.TryGetValue(instanceID, out value); float value2; bool flag2 = _beakerContentsAuditLastTotalByFillableId.TryGetValue(instanceID, out value2); string value3; bool flag3 = _beakerContentsAuditLastLabelByFillableId.TryGetValue(instanceID, out value3) && string.Equals(value3, label, StringComparison.Ordinal); bool flag4 = flag2 && Mathf.Abs(totalLiquidVolume - value2) < 0.02f; bool flag5 = flag && tickCount - value < 250; if (!(flag3 && flag4 && flag5)) { _beakerContentsAuditLastTickByFillableId[instanceID] = tickCount; _beakerContentsAuditLastTotalByFillableId[instanceID] = totalLiquidVolume; _beakerContentsAuditLastLabelByFillableId[instanceID] = label; float liquidVolume = __instance.GetLiquidVolume("pgr"); float liquidVolume2 = __instance.GetLiquidVolume("speedgrow"); float liquidVolume3 = __instance.GetLiquidVolume("fertilizer"); float liquidVolume4 = __instance.GetLiquidVolume("supergrow"); float num = (string.IsNullOrWhiteSpace(label) ? 0f : __instance.GetLiquidVolume(label)); float liquidCapacity_L = __instance.LiquidCapacity_L; LiquidContainer liquidContainer = __instance.LiquidContainer; Color val = (((Object)(object)liquidContainer != (Object)null) ? liquidContainer.LiquidColor : Color.clear); _beakerContentsAuditLogged++; MelonLogger.Msg($"SuperGrow beaker audit #{_beakerAuditSeq}: Fillable.AddLiquid label={label} delta={volume:0.###} addColor=({color.r:0.###},{color.g:0.###},{color.b:0.###},{color.a:0.###}) total={totalLiquidVolume:0.###}/{liquidCapacity_L:0.###} pgr={liquidVolume:0.###} speedgrow={liquidVolume2:0.###} fertilizer={liquidVolume3:0.###} supergrow={liquidVolume4:0.###} labelVol={num:0.###} beakerColor=({val.r:0.###},{val.g:0.###},{val.b:0.###},{val.a:0.###}) fillableId={instanceID}"); } } } catch (Exception ex) { MelonLogger.Error("SuperGrow beaker audit: Fillable.AddLiquid logging failed: " + ex.Message); } } private static StationRecipe? GetCachedSelectedRecipe(ChemistryStationInterface canvas) { try { RectTransform recipeContainer = canvas.RecipeContainer; if ((Object)(object)recipeContainer == (Object)null) { return null; } StationRecipeEntry[] componentsInChildren = ((Component)recipeContainer).GetComponentsInChildren<StationRecipeEntry>(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { return null; } foreach (StationRecipeEntry val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } StationRecipe recipe = val.Recipe; if (!((Object)(object)recipe == (Object)null)) { string text = SafeGetProductId(recipe); if (text == "supergrow") { return recipe; } } } } catch { } return null; } private static string SafeGetItemDefinitionId(ItemDefinition? def) { try { return ((BaseItemDefinition)(def?)).ID ?? "<null>"; } catch { return "<error>"; } } private static void LogRecipeIngredients(StationRecipe? recipe, int seq) { try { if ((Object)(object)recipe == (Object)null) { MelonLogger.Msg($"SuperGrow Begin audit #{seq}: recipe=<null>"); return; } string arg = SafeGetStationRecipeId(recipe); List<IngredientQuantity> ingredients = recipe.Ingredients; int num = ingredients?.Count ?? (-1); MelonLogger.Msg($"SuperGrow Begin audit #{seq}: recipeId={arg} ingredientCount={num}"); if (ingredients == null) { return; } for (int i = 0; i < ingredients.Count; i++) { IngredientQuantity val = ingredients[i]; if (val == null) { MelonLogger.Msg($"SuperGrow Begin audit #{seq}: ingredient[{i}]=<null>"); continue; } int quantity = val.Quantity; List<ItemDefinition> items = val.Items; int num2 = items?.Count ?? (-1); string text = ((items != null && items.Count > 0) ? SafeGetItemDefinitionId(items[0]) : "<none>"); MelonLogger.Msg($"SuperGrow Begin audit #{seq}: ingredient[{i}] qty={quantity} items={num2} first={text}"); if (items == null) { continue; } for (int j = 0; j < items.Count; j++) { ItemDefinition val2 = items[j]; if (!((Object)(object)val2 == (Object)null)) { string arg2 = SafeGetItemDefinitionId(val2); LogItemDefinitionPrefabState(val2, seq, $"ingredient[{i}].items[{j}] ({arg2})"); } } } } catch (Exception ex) { MelonLogger.Error($"SuperGrow Begin audit #{seq}: failed to log recipe ingredients: {ex.Message}"); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } private static void LogItemDefinitionPrefabState(ItemDefinition def, int seq, string label) { try { StorableItemDefinition val = (StorableItemDefinition)(object)((def is StorableItemDefinition) ? def : null); if ((Object)(object)val == (Object)null) { MelonLogger.Msg($"SuperGrow Begin audit #{seq}: {label} type={((object)def).GetType().FullName} storable=<null>"); return; } StationItem stationItem = val.StationItem; StoredItem storedItem = val.StoredItem; Equippable equippable = def.Equippable; string text = (((Object)(object)stationItem == (Object)null) ? "<null>" : $"{((Object)((Component)stationItem).gameObject).name} activeSelf={((Component)stationItem).gameObject.activeSelf} modules={SafeGetStationItemModuleCount(stationItem)}"); string text2 = (((Object)(object)storedItem == (Object)null) ? "<null>" : ((Object)storedItem).name); string text3 = (((Object)(object)equippable == (Object)null) ? "<null>" : ((Object)equippable).name); MelonLogger.Msg($"SuperGrow Begin audit #{seq}: {label} type={((object)def).GetType().FullName} stationItem={text} storedItem={text2} equippable={text3}"); } catch (Exception ex) { MelonLogger.Error($"SuperGrow Begin audit #{seq}: failed to inspect {label}: {ex.Message}"); } } private static int SafeGetStationItemModuleCount(StationItem stationItem) { try { return stationItem.Modules?.Count ?? (-1); } catch { return -1; } } private static void LogChemistryStationSlotState(ChemistryStation? station, int seq, string tag) { try { if ((Object)(object)station == (Object)null) { MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): station=<null>"); return; } ChemistryCookOperation currentCookOperation = station.CurrentCookOperation; string arg = ((currentCookOperation == null) ? "<null>" : (currentCookOperation.RecipeID ?? "<null>")); MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): cookOpId={arg}"); if (station.IngredientSlots != null) { for (int i = 0; i < station.IngredientSlots.Length; i++) { ItemSlot val = station.IngredientSlots[i]; ItemInstance val2 = ((val != null) ? val.ItemInstance : null); ItemDefinition val3 = ((val2 != null) ? val2.Definition : null); string text = (((Object)(object)val3 == (Object)null) ? "<null>" : SafeGetItemDefinitionId(val3)); int num = ((val2 != null) ? ((BaseItemInstance)val2).Quantity : 0); MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): slot[{i}] id={text} qty={num}"); } } else { MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): IngredientSlots=<null>"); } } catch (Exception ex) { MelonLogger.Error($"SuperGrow Begin audit #{seq} ({tag}) failed: {ex.Message}"); } } private static void LogChemistryStationIngredientTransforms(ChemistryStation station, int seq, string tag) { try { Transform[] ingredientTransforms = station.IngredientTransforms; int num = ((ingredientTransforms == null) ? (-1) : ingredientTransforms.Length); MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): ingredientTransforms={num}"); if (ingredientTransforms == null) { return; } for (int i = 0; i < ingredientTransforms.Length; i++) { Transform val = ingredientTransforms[i]; if ((Object)(object)val == (Object)null) { MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): transform[{i}]=<null>"); continue; } int childCount = val.childCount; MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): transform[{i}] name={((Object)val).name} childCount={childCount}"); for (int j = 0; j < childCount && j < 6; j++) { Transform child = val.GetChild(j); MelonLogger.Msg($"SuperGrow Begin audit #{seq} ({tag}): - child[{j}] name={((Object)child).name} activeSelf={((Component)child).gameObject.activeSelf}"); } } } catch (Exception ex) { MelonLogger.Error($"SuperGrow Begin audit #{seq} ({tag}): failed to inspect ingredient transforms: {ex.Message}"); } } private static void DumpChemistryStationInterfaceStateOnce(ChemistryStationInterface canvas, string tag, int stageMask) { if (!((Object)(object)canvas == (Object)null)) { int instanceID = ((Object)canvas).GetInstanceID(); if (!_chemCanvasDumpMaskByInstanceId.TryGetValue(instanceID, out var value) || (value & stageMask) == 0) { _chemCanvasDumpMaskByInstanceId[instanceID] = value | stageMask; DumpChemistryStationInterfaceState(canvas, tag); } } } private static void DumpChemistryStationInterfaceUiStateOnce(ChemistryStationInterface canvas, string tag, int stageMask) { if (!((Object)(object)canvas == (Object)null)) { int instanceID = ((Object)canvas).GetInstanceID(); if (!_chemCanvasDumpMaskByInstanceId.TryGetValue(instanceID, out var value) || (value & stageMask) == 0) { _chemCanvasDumpMaskByInstanceId[instanceID] = value | stageMask; DumpChemistryStationInterfaceUiState(canvas, tag); } } } private static void DumpChemistryStationInterfaceState(ChemistryStationInterface canvas, string tag) { try { int instanceID = ((Object)canvas).GetInstanceID(); object recipes = canvas.Recipes; int? num = TryGetCount(recipes); bool flag = ListContainsSuperGrowRecipe(recipes); Type typeFromHandle = typeof(ChemistryStationInterface); FieldInfo field = typeFromHandle.GetField("recipeEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); PropertyInfo propertyInfo = ((field == null) ? typeFromHandle.GetProperty("recipeEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : null); object obj = null; if (field != null) { obj = field.GetValue(canvas); } else if (propertyInfo != null) { obj = propertyInfo.GetValue(canvas); } int? num2 = TryGetCount(obj); bool flag2 = ListContainsSuperGrowRecipeEntry(obj); MelonLogger.Msg(string.Format("ChemistryStationInterface audit ({0}): canvasId={1} recipes={2} hasSuperGrowRecipe={3} recipeEntriesField={4} recipeEntries={5} hasSuperGrowEntry={6}", tag, instanceID, (recipes == null) ? "<null>" : (num?.ToString() ?? "<unknown>"), flag, (field != null) ? "ok" : ((propertyInfo != null) ? "ok(prop)" : "<missing>"), (obj == null) ? "<null>" : (num2?.ToString() ?? "<unknown>"), flag2)); } catch (Exception ex) { MelonLogger.Error("ChemistryStationInterface audit failed (" + tag + "): " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } private static void DumpChemistryStationInterfaceUiState(ChemistryStationInterface canvas, string tag) { try { int instanceID = ((Object)canvas).GetInstanceID(); RectTransform recipeContainer = canvas.RecipeContainer; if ((Object)(object)recipeContainer == (Object)null) { MelonLogger.Msg($"ChemistryStationInterface UI audit ({tag}): canvasId={instanceID} RecipeContainer=<null>"); return; } StationRecipeEntry[] componentsInChildren = ((Component)recipeContainer).GetComponentsInChildren<StationRecipeEntry>(true); int num = ((componentsInChildren != null) ? componentsInChildren.Length : 0); MelonLogger.Msg($"ChemistryStationInterface UI audit ({tag}): canvasId={instanceID} recipeContainerChildren={((Transform)recipeContainer).childCount} entryComponents={num}"); if (componentsInChildren == null || componentsInChildren.Length == 0) { return; } int num2 = 0; for (int i = 0; i < componentsInChildren.Length; i++) { if (num2 >= 12) { break; } StationRecipeEntry val = componentsInChildren[i]; if (!((Object)(object)val == (Object)null)) { string text; try { text = (((Object)(object)val.TitleLabel == (Object)null) ? "<null>" : (((TMP_Text)val.TitleLabel).text ?? "<null>")); } catch { text = "<error>"; } string text2 = SafeGetProductId(val.Recipe); MelonLogger.Msg($"ChemistryStationInterface UI entry ({tag}): idx={i} title={text} productId={text2}"); num2++; } } } catch (Exception ex) { MelonLogger.Error("ChemistryStationInterface UI audit failed (" + tag + "): " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } public static void DumpStationItemInitializePatchesOnce(string reason) { if (!_stationItemInitializePatchInfoDumped) { _stationItemInitializePatchInfoDumped = true; DumpStationItemInitializePatchInfo(reason); } } private static void DumpStationItemInitializePatchInfo(string reason) { try { MethodInfo methodInfo = AccessTools.Method(typeof(StationItem), "Initialize", new Type[1] { typeof(StorableItemDefinition) }, (Type[])null) ?? AccessTools.Method(typeof(StationItem), "Initialize", (Type[])null, (Type[])null); if (methodInfo == null) { MelonLogger.Warning("Could not resolve StationItem.Initialize method for patch audit (" + reason + ")"); return; } Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo); if (patchInfo == null) { MelonLogger.Msg("StationItem.Initialize patch audit (" + reason + "): no Harmony patches found"); return; } string text = ((patchInfo.Owners != null && patchInfo.Owners.Count > 0) ? string.Join(", ", patchInfo.Owners) : "<none>"); MelonLogger.Msg("StationItem.Initialize patch audit (" + reason + "): owners=" + text); LogPatchList("prefix", patchInfo.Prefixes); LogPatchList("postfix", patchInfo.Postfixes); LogPatchList("transpiler", patchInfo.Transpilers); LogPatchList("finalizer", patchInfo.Finalizers); } catch (Exception ex) { MelonLogger.Error("Failed to dump StationItem.Initialize patch audit (" + reason + "): " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } private static void LogPatchList(string kind, IReadOnlyCollection<Patch> patches) { if (patches == null || patches.Count == 0) { MelonLogger.Msg("StationItem.Initialize " + kind + ": <none>"); return; } MelonLogger.Msg($"StationItem.Initialize {kind}: count={patches.Count}"); foreach (Patch patch in patches) { MethodInfo patchMethod = patch.PatchMethod; string text = ((patchMethod == null) ? "<null>" : ((patchMethod.DeclaringType == null) ? patchMethod.Name : (patchMethod.DeclaringType.FullName + "." + patchMethod.Name))); MelonLogger.Msg($" - owner={patch.owner} prio={patch.priority} idx={patch.index} method={text}"); } } private static int? TryGetCount(object? listObj) { if (listObj == null) { return null; } Type type = listObj.GetType(); PropertyInfo property = type.GetProperty("Count"); if (property != null && property.PropertyType == typeof(int)) { return (int?)property.GetValue(listObj); } MethodInfo method = type.GetMethod("get_Count", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null && method.ReturnType == typeof(int)) { return (int?)method.Invoke(listObj, null); } return null; } private static object? TryGetListItem(object? listObj, int index) { if (listObj == null) { return null; } Type type = listObj.GetType(); PropertyInfo property = type.GetProperty("Item"); if (property != null) { try { return property.GetValue(listObj, new object[1] { index }); } catch { } } MethodInfo method = type.GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { try { return method.Invoke(listObj, new object[1] { index }); } catch { } } return null; } private static bool ListContainsSuperGrowRecipe(object? recipesObj) { if (recipesObj == null) { return false; } int? num = TryGetCount(recipesObj); bool flag; if (num.HasValue) { int valueOrDefault = num.GetValueOrDefault(); if (valueOrDefault > 0) { flag = false; goto IL_0037; } } flag = true; goto IL_0037; IL_0037: if (flag) { return false; } for (int i = 0; i < num; i++) { object obj = TryGetListItem(recipesObj, i); if (obj != null && TryGetStationRecipeProductId(obj, out string productId) && productId == "supergrow") { return true; } } return false; } private static bool ListContainsSuperGrowRecipeEntry(object? entriesObj) { if (entriesObj == null) { return false; } int? num = TryGetCount(entriesObj); bool flag; if (num.HasValue) { int valueOrDefault = num.GetValueOrDefault(); if (valueOrDefault > 0) { flag = false; goto IL_0037; } } flag = true; goto IL_0037; IL_0037: if (flag) { return false; } for (int i = 0; i < num; i++) { object obj = TryGetListItem(entriesObj, i); if (obj != null) { object obj2 = obj.GetType().GetProperty("Recipe", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj); if (obj2 != null && TryGetStationRecipeProductId(obj2, out string productId) && productId == "supergrow") { return true; } } } return false; } private static bool TryGetStationRecipeProductId(object recipeObj, out string? productId) { productId = null; try { MemberInfo memberInfo = (MemberInfo)(((object)recipeObj.GetType().GetProperty("Product", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) ?? ((object)recipeObj.GetType().GetField("Product", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))); if (1 == 0) { } object obj = ((memberInfo is PropertyInfo propertyInfo) ? propertyInfo.GetValue(recipeObj) : ((!(memberInfo is FieldInfo fieldInfo)) ? null : fieldInfo.GetValue(recipeObj))); if (1 == 0) { } object obj2 = obj; if (obj2 == null) { return false; } MemberInfo memberInfo2 = (MemberInfo)(((object)obj2.GetType().GetProperty("Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) ?? ((object)obj2.GetType().GetField("Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))); if (1 == 0) { } obj = ((memberInfo2 is PropertyInfo propertyInfo2) ? propertyInfo2.GetValue(obj2) : ((!(memberInfo2 is FieldInfo fieldInfo2)) ? null : fieldInfo2.GetValue(obj2))); if (1 == 0) { } object obj3 = obj; if (obj3 == null) { return false; } PropertyInfo property = obj3.GetType().GetProperty("ID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.PropertyType == typeof(string)) { productId = property.GetValue(obj3) as string; return productId != null; } FieldInfo field = obj3.GetType().GetField("ID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(string)) { productId = field.GetValue(obj3) as string; return productId != null; } MethodInfo method = obj3.GetType().GetMethod("get_ID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null && method.ReturnType == typeof(string)) { productId = method.Invoke(obj3, null) as string; return productId != null; } } catch { } return false; } private static void BeginTrashAuditWindow(int seq, ChemistryStation? station) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) _trashAuditSeq = seq; _trashAuditUntilTick = Environment.TickCount + 60000; _trashAuditTrashManagerLogged = 0; _trashAuditGetTrashPrefabLogged = 0; _trashAuditTrashItemStartLogged = 0; _trashAuditSeenTrashIds.Clear(); _trashAuditSeenGetTrashPrefabIds.Clear(); _trashAuditTrashPrefabsDumped = false; if ((Object)(object)station != (Object)null && (Object)(object)((Component)station).transform != (Object)null) { _trashAuditHasStationPos = true; _trashAuditStationPos = ((Component)station).transform.position; } else { _trashAuditHasStationPos = false; _trashAuditStationPos = Vector3.zero; } string arg = (_trashAuditHasStationPos ? ((object)Unsafe.As<Vector3, Vector3>(ref _trashAuditStationPos)/*cast due to .constrained prefix*/).ToString() : "<unknown>"); MelonLogger.Msg($"SuperGrow trash audit #{seq}: enabled for {60000}ms stationPos={arg}"); try { if ((Object)(object)_trashAuditManager == (Object)null) { _trashAuditManager = Object.FindObjectOfType<TrashManager>(); } DumpTrashPrefabsOnce("BeginTrashAuditWindow", _trashAuditManager); } catch { } } private static bool IsTrashAuditActive() { return _trashAuditUntilTick != 0 && Environment.TickCount - _trashAuditUntilTick < 0; } private static bool IsNearAuditedStation(Vector3 position) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (!_trashAuditHasStationPos) { return true; } return Vector3.Distance(position, _trashAuditStationPos) <= 35f; } private static void DumpTrashPrefabsOnce(string reason, TrashManager? manager) { if (_trashAuditTrashPrefabsDumped) { return; } if ((Object)(object)manager == (Object)null) { MelonLogger.Msg($"SuperGrow trash audit #{_trashAuditSeq}: TrashManager not found for TrashPrefabs dump ({reason})"); return; } _trashAuditTrashPrefabsDumped = true; try { TrashItem[] trashPrefabs = manager.TrashPrefabs; int num = ((trashPrefabs != null) ? trashPrefabs.Length : 0); MelonLogger.Msg($"SuperGrow trash audit #{_trashAuditSeq}: TrashPrefabs dump ({reason}) total={num}"); if (trashPrefabs != null) { for (int i = 0; i < trashPrefabs.Length; i++) { TrashItem val = trashPrefabs[i]; string arg = (((Object)(object)val == (Object)null) ? "<null>" : (val.ID ?? "<null-id>")); string arg2 = (((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null) ? "<null>" : (((Object)((Component)val).gameObject).name ?? "<unnamed>")); MelonLogger.Msg($" - [{i}] id={arg} name={arg2}"); } } } catch (Exception ex) { MelonLogger.Error("SuperGrow trash audit: TrashPrefabs dump failed (" + reason + "): " + ex.Message); } } [HarmonyPatch(typeof(ChemistryStation), "CreateTrash")] [HarmonyPrefix] private static void ChemistryStation_CreateTrash_DebugPrefix(ChemistryStation __instance, List<StationItem> mixerItems) { if (!IsTrashAuditActive()) { return; } try { ChemistryCookOperation val = ((__instance != null) ? __instance.CurrentCookOperation : null); string arg = ((val == null) ? "<null-op>" : (val.RecipeID ?? "<null>")); int num = mixerItems?.Count ?? (-1); MelonLogger.Msg($"SuperGrow trash audit #{_trashAuditSeq}: ChemistryStation.CreateTrash recipeId={arg} mixerItems={num}"); if (mixerItems == null) { return; } int num2 = Math.Min(8, mixerItems.Count); for (int i = 0; i < num2; i++) { StationItem val2 = mixerItems[i]; if ((Object)(object)val2 == (Object)null || (Object)(object)((Component)val2).gameObject == (Object)null) { MelonLogger.Msg($" - mixer[{i}]=<null>"); continue; } string arg2 = ((Object)((Component)val2).gameObject).name ?? "<unnamed>"; string arg3 = (((Object)(object)val2.TrashPrefab == (Object)null) ? "<null>" : (val2.TrashPrefab.ID ?? "<null-id>")); MelonLogger.Msg($" - mixer[{i}] name={arg2} trashId={arg3}"); } } catch (Exception ex) { MelonLogger.Error("SuperGrow trash audit: ChemistryStation.CreateTrash logging failed: " + ex.Message); } } [HarmonyPatch(typeof(TrashManager), "Start")] [HarmonyPostfix] private static void TrashManager_Start_DebugPostfix(TrashManager __instance) { _trashAuditManager = __instance; if (IsTrashAuditActive()) { DumpTrashPrefabsOnce("TrashManager.Start", __instance); } } [HarmonyPatch(typeof(TrashManager), "CreateTrashItem", new Type[] { typeof(string), typeof(Vector3), typeof(Quaternion), typeof(Vector3), typeof(string), typeof(bool) })] [HarmonyPrefix] private static void TrashManager_CreateTrashItem_DebugPrefix(string id, Vector3 posiiton, Quaternion rotation, Vector3 initialVelocity, string guid, bool startKinematic) { //IL_0029: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) if (!IsTrashAuditActive() || _trashAuditTrashManagerLogged >= 50 || !IsNearAuditedStation(posiiton)) { return; } try { string text = id ?? "<null>"; if (_trashAuditSeenTrashIds.Add(text)) { _trashAuditTrashManagerLogged++; string text2 = (_trashAuditHasStationPos ? Vector3.Distance(posiiton, _trashAuditStationPos).ToString("0.0") : "<n/a>"); MelonLogger.Msg($"SuperGrow trash audit #{_trashAuditSeq}: TrashManager.CreateTrashItem id={text} pos={posiiton} dist={text2}"); } } catch (Exception ex) { MelonLogger.Error("SuperGrow trash audit: TrashManager.CreateTrashItem logging failed: " + ex.Message); } } [HarmonyPatch(typeof(TrashManager), "GetTrashPrefab", new Type[] { typeof(string) })] [HarmonyPostfix] private static void TrashManager_GetTrashPrefab_DebugPostfix(TrashManager __instance, string id, TrashItem __result) { if (!IsTrashAuditActive() || _trashAuditGetTrashPrefabLogged >= 50) { return; } try { string text = id ?? "<null>"; if (!_trashAuditSeenGetTrashPrefabIds.Add(text)) { return; } string text2 = (((Object)(object)__result == (Object)null) ? "<null>" : (__result.ID ?? "<null-id>")); string text3 = (((Object)(object)__result == (Object)null || (Object)(object)((Component)__result).gameObject == (Object)null) ? "<null>" : (((Object)((Component)__result).gameObject).name ?? "<unnamed>")); TrashItem[] array = (((Object)(object)__instance == (Object)null) ? null : __instance.TrashPrefabs); int num = ((array != null) ? array.Length : 0); int num2 = -1; if (array != null) { for (int i = 0; i < array.Length; i++) { TrashItem val = array[i]; if ((Object)(object)val != (Object)null && val.ID == text) { num2 = i; break; } } } _trashAuditGetTrashPrefabLogged++; MelonLogger.Msg($"SuperGrow trash audit #{_trashAuditSeq}: TrashManager.GetTrashPrefab id={text} -> resultId={text2} resultName={text3} trashPrefabsIndex={num2} total={num}"); } catch (Exception ex) { MelonLogger.Error("SuperGrow trash audit: TrashManager.GetTrashPrefab logging failed: " + ex.Message); } } [HarmonyPatch(typeof(TrashItem), "Start")] [HarmonyPostfix] private static void TrashItem_Start_DebugPostfix(TrashItem __instance) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) if (!IsTrashAuditActive() || _trashAuditTrashItemStartLogged >= 50) { return; } try { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).gameObject == (Object)null)) { Vector3 val = (((Object)(object)((Component)__instance).transform != (Object)null) ? ((Component)__instance).transform.position : Vector3.zero); if (IsNearAuditedStation(val)) { _trashAuditTrashItemStartLogged++; string text = __instance.ID ?? "<null>"; string text2 = ((Object)((Component)__instance).gameObject).name ?? "<unnamed>"; string text3 = (_trashAuditHasStationPos ? Vector3.Distance(val, _trashAuditStationPos).ToString("0.0") : "<n/a>"); MelonLogger.Msg($"SuperGrow trash audit #{_trashAuditSeq}: TrashItem.Start id={text} name={text2} pos={val} dist={text3}"); } } } catch (Exception ex) { MelonLogger.Error("SuperGrow trash audit: TrashItem.Start logging failed: " + ex.Message); } } [HarmonyPatch(typeof(ChemistryStationInterface), "Awake")] [HarmonyPrefix] private static void ChemistryStationInterface_Awake_Prefix(ChemistryStationInterface __instance) { try { if ((Object)(object)__instance == (Object)null) { return; } SuperGrowCreator.CreateSuperGrowItem(); if ((Object)(object)_superGrowRecipe == (Object)null) { CreateSuperGrowRecipe(); } if ((Object)(object)_superGrowRecipe == (Object)null) { if (!_loggedRecipeNotReady) { _loggedRecipeNotReady = true; MelonLogger.Warning("SuperGrow recipe is null; cannot add to chemistry station yet"); } return; } List<StationRecipe> recipes = __instance.Recipes; if (recipes == null) { if (!_loggedRecipeNotReady) { _loggedRecipeNotReady = true; MelonLogger.Warning("ChemistryStationInterface.Recipes is null; cannot add SuperGrow recipe"); } } else if (!recipes.Contains(_superGrowRecipe)) { recipes.Add(_superGrowRecipe); MelonLogger.Msg("Added SuperGrow recipe to Chemistry Station"); SetupAdditiveStationItems(); } } catch (Exception ex) { MelonLogger.Error("Failed to add SuperGrow recipe: " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } [HarmonyPatch(typeof(ChemistryStationInterface), "Awake")] [HarmonyPostfix] private static void ChemistryStationInterface_Awake_Postfix(ChemistryStationInterface __instance) { DumpChemistryStationInterfaceStateOnce(__instance, "Awake_Postfix", 1); DumpChemistryStationInterfaceUiStateOnce(__instance, "Awake_Postfix", 4); } [HarmonyPatch(typeof(ChemistryStationInterface), "Open")] [HarmonyPrefix] private static void ChemistryStationInterface_Open_PrefixAudit(ChemistryStationInterface __instance, ChemistryStation station) { DumpChemistryStationInterfaceStateOnce(__instance, "Open_Prefix", 2); DumpChemistryStationInterfaceUiStateOnce(__instance, "Open_Prefix", 8); } [HarmonyPatch(typeof(ChemistryStationInterface), "SetSelectedRecipe")] [HarmonyPrefix] private static void ChemistryStationInterface_SetSelectedRecipe_Prefix(ChemistryStationInterface __instance, StationRecipeEntry entry) { try { StationRecipe val = ((entry != null) ? entry.Recipe : null); string text = SafeGetProductId(val); if (!(text == "<null>") && !(text == "<error>")) { _lastSelectedRecipeProductId = text; _lastSelectedRecipeTitle = SafeGetRecipeEntryTitle(entry); _lastSelectedRecipeId = (((Object)(object)val == (Object)null) ? "<null>" : SafeGetStationRecipeId(val)); _lastSelectedAtTick = Environment.TickCount; } } catch { } } [HarmonyPatch(typeof(ChemistryStationInterface), "BeginTask")] [HarmonyPrefix] private static void ChemistryStationInterface_BeginTask_Prefix(ChemistryStationInterface __instance) { try { if (!((Object)(object)__instance == (Object)null)) { StationRecipeEntry val = TryGetSelectedRecipeEntry(__instance); StationRecipe val2 = ((val != null) ? val.Recipe : null); string text = SafeGetProductId(val2); if (text == "<null>" || text == "<error>") { text = _lastSelectedRecipeProductId ?? text; } if (!(text != "supergrow")) { _superGrowBeginAuditSeq++; _superGrowBeginAuditUntilTick = Environment.TickCount + 10000; _superGrowBeginStation = __instance.ChemistryStation; _superGrowBeginStationSeq = _superGrowBeginAuditSeq; int superGrowBeginAuditSeq = _superGrowBeginAuditSeq; string text2 = (((Object)(object)val != (Object)null) ? SafeGetRecipeEntryTitle(val) : (_lastSelectedRecipeTitle ?? "<unknown>")); string text3 = (((Object)(object)val2 != (Object)null) ? SafeGetStationRecipeId(val2) : (_lastSelectedRecipeId ?? "<unknown>")); MelonLogger.Msg($"SuperGrow Begin audit #{superGrowBeginAuditSeq}: selectedTitle={text2} productId={text} recipeId={text3} beginInteractable={SafeGetBeginInteractable(__instance)}"); BeginTrashAuditWindow(superGrowBeginAuditSeq, __instance.ChemistryStation); BeginBeakerAuditWindow(superGrowBeginAuditSeq, __instance.ChemistryStation); LogRecipeIngredients(val2 ?? GetCachedSelectedRecipe(__instance), superGrowBeginAuditSeq); LogChemistryStationSlotState(_superGrowBeginStation, superGrowBeginAuditSeq, "Begin_Prefix"); } } } catch (Exception ex) { MelonLogger.Error("SuperGrow Begin audit failed (Prefix): " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } [HarmonyPatch(typeof(ChemistryStationInterface), "BeginTask")] [HarmonyPostfix] private static void ChemistryStationInterface_BeginTask_Postfix(ChemistryStationInterface __instance) { try { if (!((Object)(object)__instance == (Object)null) && !TickExpired(_superGrowBeginAuditUntilTick)) { int superGrowBeginAuditSeq = _superGrowBeginAuditSeq; ChemistryStation val = __instance.ChemistryStation; if ((Object)(object)val == (Object)null && _superGrowBeginStationSeq == superGrowBeginAuditSeq) { val = _superGrowBeginStation; } LogChemistryStationSlotState(val, superGrowBeginAuditSeq, "Begin_Postfix"); if ((Object)(object)val != (Object)null) { MelonCoroutines.Start(DelayedChemistryIngredientAudit(superGrowBeginAuditSeq, val)); } } } catch (Exception ex) { MelonLogger.Error("SuperGrow Begin audit failed (Postfix): " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } private static bool TickExpired(int untilTick) { return Environment.TickCount - untilTick >= 0; } private static IEnumerator DelayedChemistryIngredientAudit(int seq, ChemistryStation station) { yield return (object)new WaitForSeconds(0.1f); LogChemistryStationIngredientTransforms(station, seq, "Begin+0.1s"); yield return (object)new WaitForSeconds(0.4f); LogChemistryStationIngredientTransforms(station, seq, "Begin+0.5s"); yield return (object)new WaitForSeconds(0.5f); LogChemistryStationIngredientTransforms(station, seq, "Begin+1.0s"); } private static StationRecipeEntry? TryGetSelectedRecipeEntry(ChemistryStationInterface canvas) { try { Type typeFromHandle = typeof(ChemistryStationInterface); FieldInfo field = typeFromHandle.GetField("selectedRecipe", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object? value = field.GetValue(canvas); return (StationRecipeEntry?)((value is StationRecipeEntry) ? value : null); } PropertyInfo property = typeFromHandle.GetProperty("selectedRecipe", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { object? value2 = property.GetValue(canvas); return (StationRecipeEntry?)((value2 is StationRecipeEntry) ? value2 : null); } FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { if (!(fieldInfo.FieldType != typeof(StationRecipeEntry)) && !(fieldInfo.Name == "RecipeEntryPrefab") && !(fieldInfo.Name == "InProgressRecipeEntry")) { object? value3 = fieldInfo.GetValue(canvas); StationRecipeEntry val = (StationRecipeEntry)((value3 is StationRecipeEntry) ? value3 : null); if ((Object)(object)((val != null) ? val.Recipe : null) != (Object)null) { return val; } } } } catch { } return null; } private static string SafeGetRecipeEntryTitle(StationRecipeEntry? entry) { try { return ((Object)(object)entry?.TitleLabel == (Object)null) ? "<null>" : (((TMP_Text)entry.TitleLabel).text ?? "<null>"); } catch { return "<error>"; } } private static bool SafeGetBeginInteractable(ChemistryStationInterface canvas) { try { return (Object)(object)canvas.BeginButton != (Object)null && ((Selectable)canvas.BeginButton).interactable; } catch { return false; } } private static string SafeGetProductId(StationRecipe? recipe) { try { return ((BaseItemDefinition)(recipe?.Product?.Item?)).ID ?? "<null>"; } catch { return "<error>"; } } private static string SafeGetStationRecipeId(StationRecipe recipe) { try { return recipe.RecipeID ?? "<null>"; } catch { return "<error>"; } } private static void CreateSuperGrowRecipe() { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Expected O, but got Unknown //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) ItemDefinition item = Registry.GetItem("pgr"); ItemDefinition item2 = Registry.GetItem("speedgrow"); ItemDefinition item3 = Registry.GetItem("fertilizer"); ItemDefinition item4 = Registry.GetItem("supergrow"); if ((Object)(object)item == (Object)null || (Object)(object)item2 == (Object)null || (Object)(object)item3 == (Object)null) { MelonLogger.Error("Could not find one or more base additive definitions"); return; } if ((Object)(object)item4 == (Object)null) { SuperGrowCreator.CreateSuperGrowItem(); item4 = Registry.GetItem("supergrow"); if ((Object)(object)item4 == (Object)null) { MelonLogger.Warning("Could not find SuperGrow definition; will retry when registry is ready"); return; } } _superGrowRecipe = ScriptableObject.CreateInstance<StationRecipe>(); _superGrowRecipe.IsDiscovered = true; _superGrowRecipe.RecipeTitle = "SuperGrow"; _superGrowRecipe.CookTime_Mins = SuperGrowSettings.CookTimeMinutes.Value; _superGrowRecipe.Unlocked = true; List<IngredientQuantity> list = new List<IngredientQuantity>(); IngredientQuantity val = new IngredientQuantity(); List<ItemDefinition> list2 = new List<ItemDefinition>(); list2.Add(item); val.Items = list2; val.Quantity = SuperGrowSettings.PgrRequired.Value; list.Add(val); IngredientQuantity val2 = new IngredientQuantity(); List<ItemDefinition> list3 = new List<ItemDefinition>(); list3.Add(item2); val2.Items = list3; val2.Quantity = SuperGrowSettings.SpeedGrowRequired.Value; list.Add(val2); IngredientQuantity val3 = new IngredientQuantity(); List<ItemDefinition> list4 = new List<ItemDefinition>(); list4.Add(item3); val3.Items = list4; val3.Quantity = SuperGrowSettings.FertilizerRequired.Value; list.Add(val3); _superGrowRecipe.Ingredients = list; _superGrowRecipe.Product = new ItemQuantity { Item = item4, Quantity = SuperGrowSettings.OutputQuantity.Value }; _superGrowRecipe.FinalLiquidColor = SuperGrowVisuals.PourColor; } private static bool TryGetStationItemTemplate(out StationItem templateStationItem) { templateStationItem = null; string[] array = new string[4] { "acid", "pgr", "speedgrow", "fertilizer" }; string[] array2 = array; foreach (string text in array2) { ItemDefinition item = Registry.GetItem(text); StorableItemDefinition val = (StorableItemDefinition)(object)((item is StorableItemDefinition) ? item : null); if ((Object)(object)val?.StationItem != (Object)null) { templateStationItem = val.StationItem; return true; } } if (!_loggedMissingStationItemTemplate) { _loggedMissingStationItemTemplate = true; MelonLogger.Warning("Could not find any StationItem template (acid/pgr/speedgrow/fertilizer)"); string[] array3 = array; foreach (string text2 in array3) { ItemDefinition item2 = Registry.GetItem(text2); StorableItemDefinition val2 = (StorableItemDefinition)(object)((item2 is StorableItemDefinition) ? item2 : null); MelonLogger.Warning(text2 + ": def=" + (((Object)(object)val2 == (Object)null) ? "<null>" : ((object)val2).GetType().FullName) + " stationItem=" + (((Object)(object)val2?.StationItem == (Object)null) ? "<null>" : ((object)val2.StationItem).GetType().FullName)); } } return false; } [HarmonyPatch(typeof(Registry), "Start")] [HarmonyPostfix] private static void Registry_Start_Postfix() { if (_loggedRegistryStart) { return; } _loggedRegistryStart = true; try { SuperGrowCreator.CreateSuperGrowItem(); } catch (Exception ex) { MelonLogger.Error("Registry.Start hook failed: " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } public static void SetupAdditiveStationItems() { if (_additivesPatched) { return; } try { CachePourablePrefab("pgr", "growing/pgr/PGR_Pourable"); CachePourablePrefab("speedgrow", "growing/speedgrow/SpeedGrow_Pourable"); CachePourablePrefab("fertilizer", "growing/fertilizer/Fertilizer_Pourable"); if (TryGetStationItemTemplate(out StationItem templateStationItem)) { SetupAdditiveStationItem("pgr", templateStationItem); SetupAdditiveStationItem("speedgrow", templateStationItem); SetupAdditiveStationItem("fertilizer", templateStationItem); _additivesPatched = true; MelonLogger.Msg("Set up StationItem on base additives for chemistry station compatibility"); } } catch (Exception ex) { MelonLogger.Error("Failed to set up additive StationItems: " + ex.Message); MelonLogger.Error(ex.StackTrace); } } [HarmonyPatch(typeof(StoredItem), "InitializeStoredItem")] [HarmonyPostfix] private static void StoredItem_InitializeStoredItem_Postfix(StoredItem __instance, StorableItemInstance _item) { try { string text = ((_item == null) ? null : ((BaseItemDefinition)(((ItemInstance)_item).Definition?)).ID); if (!(text != "supergrow")) { ApplySuperGrowMaterialsToRenderers(((Component)__instance).GetComponentsInChildren<Renderer>(true)); } } catch (Exception ex) { MelonLogger.Error("Failed to apply SuperGrow visuals to stored item: " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } private static bool TrashPrefabsContainsId(TrashItem[]? prefabs, string id) { if (prefabs == null) { return false; } foreach (TrashItem val in prefabs) { if ((Object)(object)val != (Object)null && val.ID == id) { return true; } } return false; } private static bool TryGetMonoBottleTrashPrefab(string additiveId, out TrashItem prefab) { prefab = null; if (_monoBottleTrashPrefabByAdditiveId.TryGetValue(additiveId, out TrashItem value) && (Object)(object)value != (Object)null) { prefab = value; return true; } TrashManager val = Object.FindObjectOfType<TrashManager>(); if ((Object)(object)val == (Object)null) { return false; } EnsureMonoBottleTrashPrefabsInjected(val); if (_monoBottleTrashPrefabByAdditiveId.TryGetValue(additiveId, out value) && (Object)(object)value != (Object)null) { prefab = value; return true; } return false; } private static void EnsureMonoBottleTrashPrefabsInjected(TrashManager manager) { if (_monoTrashPrefabsInjected || (Object)(object)manager == (Object)null) { return; } try { CachePourablePrefab("pgr", "growing/pgr/PGR_Pourable"); CachePourablePrefab("speedgrow", "growing/speedgrow/SpeedGrow_Pourable"); CachePourablePrefab("fertilizer", "growing/fertilizer/Fertilizer_Pourable"); TrashItem baseTrash = manager.GetTrashPrefab("acid"); TrashItem pgrTrash = manager.GetTrashPrefab("pgr"); if ((Object)(object)baseTrash == (Object)null || (Object)(object)((Component)baseTrash).gameObject == (Object)null) { return; } TrashItem[] prefabs = manager.TrashPrefabs ?? Array.Empty<TrashItem>(); List<TrashItem> additions = new List<TrashItem>(); Ensure("pgr", "supergrow_pgr_bottle"); Ensure("speedgrow", "supergrow_speedgrow_bottle"); Ensure("fertilizer", "supergrow_fertilizer_bottle"); Ensure("supergrow", "supergrow_bottle"); if (additions.Count > 0) { TrashItem[] array = (TrashItem[])(object)new TrashItem[prefabs.Length + additions.Count]; Array.Copy(prefabs, array, prefabs.Length); for (int i = 0; i < additions.Count; i++) { array[prefabs.Length + i] = additions[i]; } manager.TrashPrefabs = array; } _monoTrashPrefabsInjected = true; void Ensure(string additiveId, string newId) { if (!TrashPrefabsContainsId(prefabs, newId)) { GameObject val = ((string.Equals(additiveId, "supergrow", StringComparison.OrdinalIgnoreCase) && (Object)(object)pgrTrash != (Object)null && (Object)(object)((Component)pgrTrash).gameObject != (Object)null) ? ((Component)pgrTrash).gameObject : ((Component)baseTrash).gameObject); GameObject val2 = Object.Instantiate<GameObject>(val); ((Object)val2).name = "SuperGrow_" + additiveId + "_TrashPrefab"; val2.SetActive(val.activeSelf); Object.DontDestroyOnLoad((Object)(object)val2); TrashItem component = val2.GetComponent<TrashItem>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val2); } else { component.ID = newId; SwapTrashItemVisualsById(additiveId, component); _monoBottleTrashPrefabByAdditiveId[additiveId] = component; additions.Add(component); } } } } catch (Exception ex) { if (!_loggedMonoTrashPrefabInjectionException) { _loggedMonoTrashPrefabInjectionException = true; MelonLogger.Warning("Failed to inject SuperGrow trash prefabs (Mono): " + ex.Message); MelonLogger.Warning(ex.StackTrace ?? "<no stack trace>"); } } } [HarmonyPatch(typeof(TrashManager), "Start")] [HarmonyPostfix] private static void TrashManager_Start_Postfix_Mono(TrashManager __instance) { EnsureMonoBottleTrashPrefabsInjected(__instance); } private static void SetPendingStationTrashReskins(List<PendingTrashReskin> reskins) { _pendingStationTrashReskins.Clear(); if (reskins.Count > 0) { _pendingStationTrashReskins.AddRange(reskins); _pendingStationTrashReskinExpireTick = Environment.TickCount + 5000; } else { _pendingStationTrashReskinExpireTick = 0; } } [HarmonyPatch(typeof(TrashItem), "Start")] [HarmonyPostfix] private static void TrashItem_Start_Postfix(TrashItem __instance) { try { if (_pendingStationTrashReskins.Count == 0) { return; } if (_pendingStationTrashReskinExpireTick != 0 && Environment.TickCount - _pendingStationTrashReskinExpireTick >= 0) { _pendingStationTrashReskins.Clear(); _pendingStationTrashReskinExpireTick = 0; return; } string iD = __instance.ID; if (string.IsNullOrEmpty(iD)) { return; } for (int i = 0; i < _pendingStationTrashReskins.Count; i++) { PendingTrashReskin pendingTrashReskin = _pendingStationTrashReskins[i]; if (!(pendingTrashReskin.TrashId != iD)) { _pendingStationTrashReskins.RemoveAt(i); SwapTrashItemVisualsById(pendingTrashReskin.AdditiveId, __instance); break; } } } catch (Exception ex) { MelonLogger.Error("Failed to apply SuperGrow visuals to trash item: " + ex.Message); MelonLogger.Error(ex.StackTrace ?? "<no stack trace>"); } } private static bool IsChemistryBeakerFillable(Fillable fillable) { if ((Object)(object)fillable == (Object)null) { return false; } LiquidContainer liquidContainer = fillable.LiquidContainer; if ((Object)(object)liquidContainer == (Object)null || (Object)(object)((Component)liquidContainer).transform == (Object)null) { return false; } Transform transform = ((Component)liquidContainer).transform; if (!string.Equals(((Object)transform).name, "Liquid", StringComparison.OrdinalIgnoreCase)) { return false; } Transform parent = transform.parent; if ((Object)(object)parent == (Object)null || !string.Equals(((Object)parent).name, "Beaker", StringComparison.OrdinalIgnoreCase)) { return false; } Transform parent2 = parent.parent; if ((Object)(object)parent2 == (Object)null || !((Object)parent2).name.StartsWith("Beaker", StringComparison.OrdinalIgnoreCase)) { return false; } Transform val = parent2; while ((Object)(object)val != (Object)null) { if (((Object)val).name != null && ((Object)val).name.IndexOf("ChemistryStation", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } val = val.parent; } return false; } private static void CachePourablePrefab(string additiveId, string pourablePath) { if (!_pourablePrefabs.ContainsKey(additiveId)) { GameObject val = Resources.Load<GameObject>(pourablePath); if ((Object)(object)val != (Object)null) { _pourablePrefabs[additiveId] = val; MelonLogger.Msg("Cached pourable prefab for " + additiveId); } else { MelonLogger.Warning("Could not load pourable prefab for " + additiveId + " at " + pourablePath); } } } private static Transform? FindStationItemBottleContainer(StationItem stationItem) { Transform val = ((Component)stationItem).transform.Find("Pourable"); if ((Object)(object)val == (Object)null) { return null; } Transform result = null; int childCount = val.childCount; for (int i = 0; i < childCount; i++) { Transform child = val.GetChild(i); if ((Object)(object)child != (Object)null && ((Object)child).name.IndexOf("Bottle", StringComparison.OrdinalIgnoreCase) >= 0) { result = child; break; } } return result; } private static void SwapBottleMeshesAndMaterials(GameObject templatePrefab, Transform targetRoot) { MeshFilter[] componentsInChildren = templatePrefab.GetComponentsInChildren<MeshFilter>(true); MeshFilter[] componentsInChildren2 = ((Component)targetRoot).GetComponentsInChildren<MeshFilter>(true); MeshFilter[] array = componentsInChildren2; foreach (MeshFilter val in array) { if ((Object)(object)val == (Object)null) { continue; } string text = ((Object)val).name.ToLowerInvariant(); MeshFilter[] array2 = componentsInChildren; foreach (MeshFilter val2 in array2) { if ((Object)(object)val2 == (Object)null) { continue; } string text2 = ((Object)val2).name.ToLowerInvariant(); if ((text.Contains("body") && text2.Contains("body")) || (text.Contains("label") && text2.Contains("label")) || (text.Contains("lid") && text2.Contains("lid"))) { val.sharedMesh = val2.sharedMesh; MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>(); MeshRenderer component2 = ((Component)val2).GetComponent<MeshRenderer>(); if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null) { ((Renderer)component).sharedMaterials = ((Renderer)component2).sharedMaterials; } break; } } } } private static void ApplySuperGrowMaterialsToRenderers(Renderer[]? renderers) { SuperGrowVisuals.ApplySuperGrowMaterialsToRenderers(renderers); } private static void SetupAdditiveStationItem(string additiveId, StationItem templateStationItem) { ItemDefinition item = Registry.GetItem(additiveId); StorableItemDefinition val = (StorableItemDefinition)(object)((item is StorableItemDefinition) ? item : null); if ((Object)(object)val == (Object)null) { MelonLogger.Warning("Could not find additive: " + additiveId); } else if (!((Object)(object)val.StationItem != (Object)null)) { val.StationItem = templateStationItem; } } private static void SwapTrashItemVisualsById(string id, TrashItem trashItem) { if ((Object)(object)trashItem == (Object)null || string.IsNullOrEmpty(id)) { return; } bool flag = id == "supergrow"; if (!flag && id != "pgr" && id != "speedgrow" && id != "fertilizer") { return; } GameObject value = null; if (flag) { _pourablePrefabs.TryGetValue("pgr", out value); } else { _pourablePrefabs.TryGetValue(id, out value); } if ((Object)(object)value == (Object)null) { return; } try { if (!((Object)(object)((Component)trashItem).transform == (Object)null)) { SwapBottleMeshesAndMaterials(value, ((Component)trashItem).transform); if (flag) { ApplySuperGrowMaterialsToRenderers(((Component)trashItem).GetComponentsInChildren<Renderer>(true)); } } } catch (Exception ex) { MelonLogger.Error("Failed to swap trash visuals for " + id + ": " + ex.Message); MelonLogger.Error(ex.StackTrace); } } private static void SwapStationItemVisualsById(string id, StationItem stationItem) { //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)stationItem == (Object)null || string.IsNullOrEmpty(id)) { return; } bool flag = id == "supergrow"; if (!flag && id != "pgr" && id != "speedgrow" && id != "fertilizer") { return; } GameObject value = null; if (flag) { _pourablePrefabs.TryGetValue("pgr", out value); } else { _pourablePrefabs.TryGetValue(id, out value); } if ((Object)(object)value == (Object)null) { return; } try { Transform val = FindStationItemBottleContainer(stationItem); if ((Object)(object)val == (Object)null) { return; } SwapBottleMeshesAndMaterials(value, val); if (flag) { ApplySuperGrowMaterialsToRenderers(((Component)val).GetComponentsInChildren<Renderer>(true)); } object obj; if (!((Object)(object)((Component)stationItem).transform != (Object)null)) { obj = null; } else { Transform obj2 = ((Component)stationItem).transform.Find("Pourable"); obj = ((obj2 != null) ? ((Component)obj2).GetComponent<PourableModule>() : null); } PourableModule val2 = (PourableModule)obj; if ((Object)(object)val2 != (Object)null && (Object)(object)val2.LiquidContainer != (Object)null) { LiquidContainer liquidContainer = val2.LiquidContainer; if ((Object)(object)liquidContainer.LiquidVolume != (Object)null) { Transform transform = ((Component)liquidContainer.LiquidVolume).transform; transform.localScale *= 0.65f; } liquidContainer.MaxLevel *= 0.65f; if (_additiveColors.TryGetValue(id, out var value2)) { val2.LiquidType = id; val2.LiquidColor = value2; val2.PourParticlesColor = value2; liquidContainer.SetLiquidColor(value2, true, true); } } if (!flag && (id == "pgr" || id == "speedgrow" || id == "fertilizer") && TryGetMonoBottleTrashPrefab(id, out TrashItem prefab)) { stationItem.TrashPrefab = prefab; } } catch (Exception ex) { MelonLogger.Error("Failed to swap station item visuals for " + id + ": " + ex.Message); MelonLogger.Error(ex.StackTrace); } } private static void SwapStationItemVisualsById(string id, StationItem stationItem, StorableItemDefinition itemDef) { if (!((Object)(object)stationItem == (Object)null) && !((Object)(object)itemDef == (Object)null)) { SwapStationItemVisualsById(id, stationItem); } } private static void SwapStationItemVisuals(StationItem stationItem, StorableItemDefinition itemDef) { string iD = ((BaseItemDefinition)itemDef).ID; SwapStationItemVisualsById(iD, stationItem, itemDef); } [HarmonyPatch(typeof(StationItem), "Initialize")] [HarmonyPostfix] private static void StationItem_Initialize_Postfix(StationItem __instance, StorableItemDefinition itemDefinition) { SwapStationItemVisuals(__instance, itemDefinition); } } [HarmonyPatch] internal static class GrowContainerPatches { private static readonly string[] SuperGrowSupersededAdditiveIds = new string[3] { "pgr", "speedgrow", "fertilizer" }; private const string SuperGrowBottleTrashId = "supergrow_bottle"; private static bool _loggedGrowContainerTrashPrefabAssignException; private static readonly Vector3 HiddenPrefabPosition = new Vector3(100000f, 100000f, 100000f); private static Pourable? _superGrowPourablePrefab; private const int MaxTaskLogs = 50; private const int MaxTrashLogs = 200; private const int TrashLogWindowSize = 40; private static int _taskLogCount; private static int _trashLogCount; private static int _trashLogWindowRemaining; private static readonly HashSet<string> _loggedOnceKeys = new HashSet<string>(); private static int _removeItemDepth; private static bool _shouldReskinNextTrashSpawn; private static readonly HashSet<string> _loggedReskinnedTrashIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase); [HarmonyPatch(typeof(GrowContainer), "CanApplyAdditive")] [HarmonyPrefix] private static bool GrowContainer_CanApplyAdditive_Prefix(GrowContainer __instance, AdditiveDefinition additiveDef, out string invalidReason, ref bool __result) { invalidReason = string.Empty; try { if ((Object)(object)__instance != (Object)null && (Object)(object)additiveDef != (Object)null && Array.IndexOf(SuperGrowSupersededAdditiveIds, ((BaseItemDefinition)additiveDef).ID) >= 0 && __instance.IsAdditiveApplied("supergrow")) { invalidReason = "Already contains SuperGrow"; __result = false; return false; } } catch (Exception ex) { MelonLogger.Error("SuperGrow additive exclusivity check failed: " + ex.Message); } return true; } private static void InjectSuperGrowIntoAllowedAdditives(GrowContainer container) { try { ItemDefinition item = Registry.GetItem("supergrow"); AdditiveDefinition val = (AdditiveDefinition)(object)((item is AdditiveDefinition) ? item : null); if ((Object)(object)val == (Object)null) { return; } if (container.AllowedAdditives != null) { AdditiveDefinition[] allowedAdditives = container.AllowedAdditives; foreach (AdditiveDefinition val2 in allowedAdditives) { if ((Object)(object)val2 != (Object)null && ((BaseItemDefinition)val2).ID == "supergrow") { return; } } } AdditiveDefinition[] array = container.AllowedAdditives ?? Array.Empty<AdditiveDefinition>(); AdditiveDefinition[] array2 = (AdditiveDefinition[])(object)new AdditiveDefinition[array.Length + 1]; array.CopyTo(array2, 0); array2[^1] = val; container.AllowedAdditives = array2; } catch (Exception ex) { MelonLogger.Error("Failed to inject SuperGrow into AllowedAdditives: " + ex.Message); } } [HarmonyPatch(typeof(GrowContainer), "InitializeGridItem")] [HarmonyPrefix] private static void GrowContainer_InitializeGridItem_Prefix(GrowContainer __instance) { InjectSuperGrowIntoAllowedAdditives(__instance); } private static Pourable? GetOrCreateSuperGrowPourablePrefab(Pourable basePrefab) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_superGrowPourablePrefab != (Object)null && (Object)(object)((Component)_superGrowPourablePrefab).gameObject != (Object)null) { return _superGrowPourablePrefab; } if ((Object)(object)basePrefab == (Object)null || (Object)(object)((Component)basePrefab).gameObject == (Object)null) { return null; } try { GameObject val = Object.Instantiate<GameObject>(((Component)basePrefab).gameObject); ((Object)val).name = "SuperGrow_PourablePrefab"; ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val); val.transform.position = HiddenPrefabPosition; if (!val.activeSelf) { val.SetActive(true); } Pourable component = val.GetComponent<Pourable>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val); return null; } PourableAdditive component2 = val.GetComponent<PourableAdditive>(); if ((Object)(object)component2 != (Object)null) { component2.LiquidColor = SuperGrowVisuals.PourColor; } ParticleSystem[] componentsInChildren = val.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null)) { MainModule main = val2.main; ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(SuperGrowVisuals.PourColor); } } SuperGrowVisuals.ApplySuperGrowMaterialsToRenderers(val.GetComponentsInChildren<Renderer>(true)); try { TrashManager val3 = Object.FindObjectOfType<TrashManager>(); if ((Object)(object)val3 != (Object)null) { TrashItem trashPrefab = val3.GetTrashPrefab("supergrow_bottle"); if ((Object)(object)trashPrefab != (Object)null) { component.TrashItem = trashPrefab; } } } catch (Exception ex) { if (!_loggedGrowContainerTrashPrefabAssignException) { _loggedGrowContainerTrashPrefabAssignException = true; MelonLogger.Warning("Failed to assign SuperGrow trash prefab to grow-container pourable: " + ex.Message); MelonLogger.Warning(ex.StackTrace ?? "<no stack trace>"); } } _superGrowPourablePrefab = component; return _superGrowPourablePrefab; } catch (Exception ex2) { MelonLogger.Error("Failed to create SuperGrow pourable prefab: " + ex2.Message); MelonLogger.Error(ex2.StackTrace); return null; } } private static void LogOnce(string key, string message) { if (_loggedOnceKeys.Add(key)) { LogImportant(message); } } private static void LogImportant(string message) { MelonLogger.Msg("[GrowContainerPatches.Diagnostics] " + message); } private static void LogTask(string message) { if (_taskLogCount < 50) { _taskLogCount++; MelonLogger.Msg("[GrowContainerPatches.Diagnostics] " + message); } } private static void LogTrash(string message) { if (_trashLogCount < 200) { _trashLogCount++; MelonLogger.Msg("[GrowContainerPatches.Diagnostics] " + message); } } private static void OpenTrashLogWindow() { _trashLogWindowRemaining = 40; } private static bool ShouldLogTrash(string requestedId) { if (_trashLogWindowRemaining > 0) { _trashLogWindowRemaining--; return true; } if (string.IsNullOrWhiteSpace(requestedId)) { return false; } string text = requestedId.Trim(); if (text.Equals("pgr", StringComparison.OrdinalIgnoreCase) || text.Equals("acid", StringComparison.OrdinalIgnoreCase) || text.Contains("supergrow", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } private static void DumpTaskState(string hook, object task) { if (task == null) { LogTask(hook + ": <null task>"); return; } Type type = task.GetType(); string text = type.FullName ?? type.Name; string text2 = "<unknown>"; string text3 = "<unknown>"; string text4 = "<unknown>"; try { FieldInfo field = type.GetField("item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); PropertyInfo propertyInfo = ((field == null) ? type.GetProperty("item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : null); object obj = field?.GetValue(task) ?? propertyInfo?.GetValue(task); if (obj != null) { Type type2 = obj.GetType(); object obj2 = AccessTools.Property(type2, "Definition")?.GetValue(obj); if (obj2 != null) { text2 = (AccessTools.Property(obj2.GetType(), "ID")?.GetValue(obj2) as string) ?? text2; } text2 = (AccessTools.Property(type2, "ID")?.GetValue(obj) as string) ?? text2; } FieldInfo field2 = type.GetField("pourable", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); PropertyInfo propertyInfo2 = ((field2 == null) ? type.GetProperty("pourable", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : null); object obj3 = field2?.GetValue(task) ?? propertyInfo2?.GetValue(task); if (obj3 != null) { Type type3 = obj3.GetType(); text3 = type3.FullName ?? type3.Name; object obj4 = AccessTools.Property(type3, "TrashItem")?.GetValue(obj3); if (obj4 != null) { Type type4 = obj4.GetType(); text4 = (type4.GetField("ID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj4) as string) ?? text4; text4 = (type4.GetProperty("ID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj4) as string) ?? text4; } } } catch (Exception ex) { LogOnce("DumpTaskStateError:" + text, hook + ": error dumping task state for " + text + ": " + ex.GetType().Name + ": " + ex.Message); } LogTask(hook + ": task=" + text + " itemId=" + text2 + " pourable=" + text3 + " trashId=" + text4); } [HarmonyPatch(typeof(GrowContainerPourTask), "OnInitialPour")] [HarmonyPostfix] private static void GrowContainerPourTask_OnIni