diff --git a/AbsorbentSoil/AbsorbentSoilMod.cs b/AbsorbentSoil/AbsorbentSoilMod.cs index ee9a8ae..4786335 100644 --- a/AbsorbentSoil/AbsorbentSoilMod.cs +++ b/AbsorbentSoil/AbsorbentSoilMod.cs @@ -4,11 +4,13 @@ using System.Linq; using System.Reflection; using HarmonyLib; using MelonLoader; +using Il2CppInterop.Runtime; using Il2CppScheduleOne.Growing; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.ObjectScripts; +using UnityEngine; -[assembly: MelonInfo(typeof(AbsorbentSoil.AbsorbentSoilMod), "Absorbent Soil", "0.1.1", "AttilaG")] +[assembly: MelonInfo(typeof(AbsorbentSoil.AbsorbentSoilMod), "Absorbent Soil", "0.1.0", "AttilaG")] [assembly: MelonGame(null, "Schedule I")] namespace AbsorbentSoil @@ -22,15 +24,16 @@ namespace AbsorbentSoil MelonLogger.Msg("Absorbent Soil loaded. Additive retention is active for long-life soils."); } + // This keeps slot/session bleed low if the player backs out and loads another save without restarting. + // It does NOT persist anything to disk. It only tracks pots currently seen in the running game session. public override void OnSceneWasLoaded(int buildIndex, string sceneName) { - // Prevent save-slot/session bleed if the player returns to menu and loads another save. if (!string.IsNullOrWhiteSpace(sceneName) && (sceneName.IndexOf("menu", StringComparison.OrdinalIgnoreCase) >= 0 || sceneName.IndexOf("main", StringComparison.OrdinalIgnoreCase) >= 0 || sceneName.IndexOf("load", StringComparison.OrdinalIgnoreCase) >= 0)) { - AdditiveMemory.ClearAll(); + AdditiveMemory.Clear(); MelonLogger.Msg($"Cleared additive memory on scene load: {sceneName}"); } } @@ -73,27 +76,28 @@ namespace AbsorbentSoil : Array.Empty(); } + public static bool HasStored(Pot pot) + { + if (pot == null) + return false; + + string key = PotKeyHelper.GetPotKey(pot); + return !string.IsNullOrWhiteSpace(key) && + AdditivesByPotKey.TryGetValue(key, out HashSet set) && + set.Count > 0; + } + public static void Forget(Pot pot) { if (pot == null) return; - Forget(PotKeyHelper.GetPotKey(pot)); + string key = PotKeyHelper.GetPotKey(pot); + if (!string.IsNullOrWhiteSpace(key)) + AdditivesByPotKey.Remove(key); } - public static void Forget(string potKey) - { - if (string.IsNullOrWhiteSpace(potKey)) - return; - - if (AdditivesByPotKey.Remove(potKey) && AbsorbentSoilMod.VerboseLogging) - MelonLogger.Msg($"Cleared retained additives for pot '{potKey}'."); - } - - public static void ClearAll() - { - AdditivesByPotKey.Clear(); - } + public static void Clear() => AdditivesByPotKey.Clear(); } internal static class PotKeyHelper @@ -103,10 +107,13 @@ namespace AbsorbentSoil if (pot == null) return string.Empty; + // Most Schedule I buildable/grid items have a GUID inherited from a base class. + // Use reflection so this survives minor EA API shifts. object guid = ReadMember(pot, "GUID") ?? ReadMember(pot, "Guid") ?? ReadMember(pot, "guid"); if (guid != null && !string.IsNullOrWhiteSpace(guid.ToString())) return guid.ToString(); + // Fallback for testing only. Not stable across reloads, but better than hard failing. return $"scene:{pot.GetInstanceID()}"; } @@ -116,21 +123,17 @@ namespace AbsorbentSoil return null; Type type = instance.GetType(); - while (type != null) + + PropertyInfo prop = AccessTools.Property(type, name); + if (prop != null) { - PropertyInfo prop = AccessTools.Property(type, name); - if (prop != null) - { - try { return prop.GetValue(instance); } catch { } - } + try { return prop.GetValue(instance); } catch { } + } - FieldInfo field = AccessTools.Field(type, name); - if (field != null) - { - try { return field.GetValue(instance); } catch { } - } - - type = type.BaseType; + FieldInfo field = AccessTools.Field(type, name); + if (field != null) + { + try { return field.GetValue(instance); } catch { } } return null; @@ -142,28 +145,30 @@ namespace AbsorbentSoil private static readonly FieldInfo RemainingSoilUsesField = AccessTools.Field(typeof(GrowContainer), "_remainingSoilUses"); - public static bool IsRetainingSoil(Pot pot) - { - if (pot == null || string.IsNullOrWhiteSpace(pot.SoilID)) - return false; - - string soilId = pot.SoilID.ToLowerInvariant(); - - return soilId.Contains("longlifesoil") || - soilId.Contains("extralonglifesoil"); - } - public static int GetRemainingSoilUses(Pot pot) { if (pot == null || RemainingSoilUsesField == null) return 0; - return (int)RemainingSoilUsesField.GetValue(pot); + try + { + return (int)RemainingSoilUsesField.GetValue(pot); + } + catch + { + return 0; + } } - public static bool CanRetainAdditives(Pot pot) + public static bool CanCaptureNewAdditives(Pot pot) { - return IsRetainingSoil(pot) && GetRemainingSoilUses(pot) > 0; + // Normal soil should have 1 use, long-life should have more than 1. + return GetRemainingSoilUses(pot) > 1; + } + + public static bool CanReapplyRetainedAdditives(Pot pot) + { + return GetRemainingSoilUses(pot) > 0; } } @@ -171,7 +176,6 @@ namespace AbsorbentSoil internal static class Pot_ApplyAdditive_Patch { private static bool _suppressCapture; - private static readonly MethodInfo ApplyAdditiveMethod = AccessTools.Method(typeof(Pot), "ApplyAdditive"); public static void Postfix(Pot __instance, AdditiveDefinition __result, string additiveID, bool isInitialApplication) { @@ -183,7 +187,7 @@ namespace AbsorbentSoil if (__instance == null || __result == null || string.IsNullOrWhiteSpace(additiveID)) return; - if (!SoilHelper.IsRetainingSoil(__instance)) + if (!SoilHelper.CanCaptureNewAdditives(__instance)) return; AdditiveMemory.Remember(__instance, additiveID); @@ -199,7 +203,8 @@ namespace AbsorbentSoil if (pot == null || string.IsNullOrWhiteSpace(additiveID)) return; - if (ApplyAdditiveMethod == null) + MethodInfo applyAdditive = AccessTools.Method(typeof(Pot), "ApplyAdditive"); + if (applyAdditive == null) { MelonLogger.Warning("Could not find Pot.ApplyAdditive via reflection."); return; @@ -208,7 +213,7 @@ namespace AbsorbentSoil try { _suppressCapture = true; - ApplyAdditiveMethod.Invoke(pot, new object[] { additiveID, true }); + applyAdditive.Invoke(pot, new object[] { additiveID, true }); } catch (Exception ex) { @@ -232,12 +237,8 @@ namespace AbsorbentSoil return; Pot pot = __instance.Pot; - - if (!SoilHelper.CanRetainAdditives(pot)) - { - AdditiveMemory.Forget(pot); + if (!SoilHelper.CanReapplyRetainedAdditives(pot)) return; - } IReadOnlyList additiveIds = AdditiveMemory.Get(pot); if (additiveIds.Count == 0) @@ -258,15 +259,33 @@ namespace AbsorbentSoil [HarmonyPatch(typeof(Pot), "OnPlantFullyHarvested")] internal static class Pot_OnPlantFullyHarvested_Patch { - private static void Postfix(Pot __instance) + public static void Postfix(Pot __instance) { - if (__instance == null) - return; + // Intentionally do nothing. This patch exists as a reminder that retained additives should survive harvest. + // Do NOT clear AdditiveMemory here, because long-life/extra-long-life soil should carry additives forward. + } + } - if (!SoilHelper.CanRetainAdditives(__instance)) + [HarmonyPatch(typeof(GrowContainer), "SetRemainingSoilUses")] + internal static class GrowContainer_SetRemainingSoilUses_Patch + { + private static void Postfix(GrowContainer __instance, int uses) + { + try { - AdditiveMemory.Forget(__instance); - MelonLogger.Msg("[Absorbent Soil] Cleared retained additives because soil has no retaining uses left."); + if (__instance == null || uses > 0) + return; + + Pot pot = __instance.TryCast(); + if (pot == null) + return; + + AdditiveMemory.Forget(pot); + MelonLogger.Msg("[Absorbent Soil] Cleared retained additives because soil uses reached zero."); + } + catch (Exception ex) + { + MelonLogger.Warning($"SetRemainingSoilUses postfix failed: {ex}"); } } } @@ -276,6 +295,7 @@ namespace AbsorbentSoil { public static void Prefix(Pot __instance) { + // If the pot itself is destroyed/sold, stop tracking its additives. try { AdditiveMemory.Forget(__instance); } catch { } } diff --git a/AbsorbentSoil/bin/Release/net6.0/AbsorbentSoil.deps.json b/AbsorbentSoil/bin/Release/net6.0/AbsorbentSoil.deps.json new file mode 100644 index 0000000..074dff0 --- /dev/null +++ b/AbsorbentSoil/bin/Release/net6.0/AbsorbentSoil.deps.json @@ -0,0 +1,23 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v6.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v6.0": { + "AbsorbentSoil/1.0.0": { + "runtime": { + "AbsorbentSoil.dll": {} + } + } + } + }, + "libraries": { + "AbsorbentSoil/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/AbsorbentSoil/bin/Release/net6.0/AbsorbentSoil.pdb b/AbsorbentSoil/bin/Release/net6.0/AbsorbentSoil.pdb new file mode 100644 index 0000000..74111c8 Binary files /dev/null and b/AbsorbentSoil/bin/Release/net6.0/AbsorbentSoil.pdb differ diff --git a/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.AssemblyInfo.cs b/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.AssemblyInfo.cs index 7b132cd..7699a91 100644 --- a/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.AssemblyInfo.cs +++ b/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.AssemblyInfo.cs @@ -13,7 +13,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("AbsorbentSoil")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+57f6a7917f7640bd65cefb3f66b24ea34b817e0c")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+3c7ea09f730c3ca38d3c004961f111503e0905c8")] [assembly: System.Reflection.AssemblyProductAttribute("AbsorbentSoil")] [assembly: System.Reflection.AssemblyTitleAttribute("AbsorbentSoil")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.AssemblyInfoInputs.cache b/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.AssemblyInfoInputs.cache index d6bf4c6..e5d73e1 100644 --- a/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.AssemblyInfoInputs.cache +++ b/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.AssemblyInfoInputs.cache @@ -1 +1 @@ -8a3855f139cd66387b0e747834f0fb38e6416f2dc381e733183dbdeaa1f21465 +b331521ed94e421a5866942ca81a55cff8e0735dcb4bc556f934ca310386ca0f diff --git a/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.csproj.FileListAbsolute.txt b/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.csproj.FileListAbsolute.txt index e6c9830..96cd45d 100644 --- a/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.csproj.FileListAbsolute.txt +++ b/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.csproj.FileListAbsolute.txt @@ -1,5 +1,12 @@ +/home/attila/Projects/Schedule-1/AbsorbentSoilMod/AbsorbentSoil/bin/Release/net6.0/AbsorbentSoil.deps.json +/home/attila/Projects/Schedule-1/AbsorbentSoilMod/AbsorbentSoil/bin/Release/net6.0/AbsorbentSoil.dll +/home/attila/Projects/Schedule-1/AbsorbentSoilMod/AbsorbentSoil/bin/Release/net6.0/AbsorbentSoil.pdb /home/attila/Projects/Schedule-1/AbsorbentSoilMod/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.csproj.AssemblyReference.cache /home/attila/Projects/Schedule-1/AbsorbentSoilMod/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.GeneratedMSBuildEditorConfig.editorconfig /home/attila/Projects/Schedule-1/AbsorbentSoilMod/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.AssemblyInfoInputs.cache /home/attila/Projects/Schedule-1/AbsorbentSoilMod/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.AssemblyInfo.cs /home/attila/Projects/Schedule-1/AbsorbentSoilMod/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.csproj.CoreCompileInputs.cache +/home/attila/Projects/Schedule-1/AbsorbentSoilMod/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.dll +/home/attila/Projects/Schedule-1/AbsorbentSoilMod/AbsorbentSoil/obj/Release/net6.0/refint/AbsorbentSoil.dll +/home/attila/Projects/Schedule-1/AbsorbentSoilMod/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.pdb +/home/attila/Projects/Schedule-1/AbsorbentSoilMod/AbsorbentSoil/obj/Release/net6.0/ref/AbsorbentSoil.dll diff --git a/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.dll b/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.dll new file mode 100644 index 0000000..9000eee Binary files /dev/null and b/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.dll differ diff --git a/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.pdb b/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.pdb new file mode 100644 index 0000000..74111c8 Binary files /dev/null and b/AbsorbentSoil/obj/Release/net6.0/AbsorbentSoil.pdb differ diff --git a/AbsorbentSoil/obj/Release/net6.0/ref/AbsorbentSoil.dll b/AbsorbentSoil/obj/Release/net6.0/ref/AbsorbentSoil.dll new file mode 100644 index 0000000..d656e87 Binary files /dev/null and b/AbsorbentSoil/obj/Release/net6.0/ref/AbsorbentSoil.dll differ diff --git a/AbsorbentSoil/obj/Release/net6.0/refint/AbsorbentSoil.dll b/AbsorbentSoil/obj/Release/net6.0/refint/AbsorbentSoil.dll new file mode 100644 index 0000000..d656e87 Binary files /dev/null and b/AbsorbentSoil/obj/Release/net6.0/refint/AbsorbentSoil.dll differ