0.1.1
This commit is contained in:
@@ -4,12 +4,11 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using ScheduleOne.Growing;
|
using Il2CppScheduleOne.Growing;
|
||||||
using ScheduleOne.ItemFramework;
|
using Il2CppScheduleOne.ItemFramework;
|
||||||
using ScheduleOne.ObjectScripts;
|
using Il2CppScheduleOne.ObjectScripts;
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
[assembly: MelonInfo(typeof(AbsorbentSoil.AbsorbentSoilMod), "Absorbent Soil", "0.1.0", "AttilaG")]
|
[assembly: MelonInfo(typeof(AbsorbentSoil.AbsorbentSoilMod), "Absorbent Soil", "0.1.1", "AttilaG")]
|
||||||
[assembly: MelonGame(null, "Schedule I")]
|
[assembly: MelonGame(null, "Schedule I")]
|
||||||
|
|
||||||
namespace AbsorbentSoil
|
namespace AbsorbentSoil
|
||||||
@@ -23,16 +22,15 @@ namespace AbsorbentSoil
|
|||||||
MelonLogger.Msg("Absorbent Soil loaded. Additive retention is active for long-life soils.");
|
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)
|
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) &&
|
if (!string.IsNullOrWhiteSpace(sceneName) &&
|
||||||
(sceneName.IndexOf("menu", StringComparison.OrdinalIgnoreCase) >= 0 ||
|
(sceneName.IndexOf("menu", StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
sceneName.IndexOf("main", StringComparison.OrdinalIgnoreCase) >= 0 ||
|
sceneName.IndexOf("main", StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
sceneName.IndexOf("load", StringComparison.OrdinalIgnoreCase) >= 0))
|
sceneName.IndexOf("load", StringComparison.OrdinalIgnoreCase) >= 0))
|
||||||
{
|
{
|
||||||
AdditiveMemory.Clear();
|
AdditiveMemory.ClearAll();
|
||||||
MelonLogger.Msg($"Cleared additive memory on scene load: {sceneName}");
|
MelonLogger.Msg($"Cleared additive memory on scene load: {sceneName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,12 +78,22 @@ namespace AbsorbentSoil
|
|||||||
if (pot == null)
|
if (pot == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string key = PotKeyHelper.GetPotKey(pot);
|
Forget(PotKeyHelper.GetPotKey(pot));
|
||||||
if (!string.IsNullOrWhiteSpace(key))
|
|
||||||
AdditivesByPotKey.Remove(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Clear() => AdditivesByPotKey.Clear();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class PotKeyHelper
|
internal static class PotKeyHelper
|
||||||
@@ -95,13 +103,10 @@ namespace AbsorbentSoil
|
|||||||
if (pot == null)
|
if (pot == null)
|
||||||
return string.Empty;
|
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");
|
object guid = ReadMember(pot, "GUID") ?? ReadMember(pot, "Guid") ?? ReadMember(pot, "guid");
|
||||||
if (guid != null && !string.IsNullOrWhiteSpace(guid.ToString()))
|
if (guid != null && !string.IsNullOrWhiteSpace(guid.ToString()))
|
||||||
return guid.ToString();
|
return guid.ToString();
|
||||||
|
|
||||||
// Fallback for testing only. Not stable across reloads, but better than hard failing.
|
|
||||||
return $"scene:{pot.GetInstanceID()}";
|
return $"scene:{pot.GetInstanceID()}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,92 +116,6 @@ namespace AbsorbentSoil
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
Type type = instance.GetType();
|
Type type = instance.GetType();
|
||||||
|
|
||||||
PropertyInfo prop = AccessTools.Property(type, name);
|
|
||||||
if (prop != null)
|
|
||||||
{
|
|
||||||
try { return prop.GetValue(instance); } catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldInfo field = AccessTools.Field(type, name);
|
|
||||||
if (field != null)
|
|
||||||
{
|
|
||||||
try { return field.GetValue(instance); } catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static class SoilHelper
|
|
||||||
{
|
|
||||||
// Adjust these after checking the actual IDs/names from item definitions or Melon logs.
|
|
||||||
// The helper checks IDs/names case-insensitively and allows partial matches.
|
|
||||||
private static readonly string[] RetainingSoilTokens =
|
|
||||||
{
|
|
||||||
"longlife",
|
|
||||||
"long_life",
|
|
||||||
"long-life",
|
|
||||||
"long life",
|
|
||||||
"extralonglife",
|
|
||||||
"extra_long_life",
|
|
||||||
"extra-long-life",
|
|
||||||
"extra long life"
|
|
||||||
};
|
|
||||||
|
|
||||||
public static bool IsRetainingSoil(Pot pot)
|
|
||||||
{
|
|
||||||
if (pot == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// In current Pot.cs, soil identity is probably on GrowContainer/PotData/base state rather than Pot itself.
|
|
||||||
// Try several likely member names so the mod remains resilient to EA renames.
|
|
||||||
foreach (string memberName in new[]
|
|
||||||
{
|
|
||||||
"SoilID", "soilID", "SoilId", "soilId",
|
|
||||||
"SoilDefinition", "soilDefinition", "SoilItem", "soilItem",
|
|
||||||
"Soil", "soil", "CurrentSoil", "currentSoil"
|
|
||||||
})
|
|
||||||
{
|
|
||||||
object value = ReadMemberRecursive(pot, memberName);
|
|
||||||
if (MatchesRetainingSoil(value))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Last resort: inspect chunks/transforms/names. This is intentionally broad but only affects whether
|
|
||||||
// additives are remembered/reapplied; if it is too broad, tighten RetainingSoilTokens above.
|
|
||||||
string potName = SafeLower(pot.name);
|
|
||||||
if (ContainsAnyToken(potName))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool MatchesRetainingSoil(object value)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (ContainsAnyToken(SafeLower(value.ToString())))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
foreach (string memberName in new[] { "ID", "Id", "Name", "name", "ItemID", "itemID", "Definition", "definition" })
|
|
||||||
{
|
|
||||||
object nested = ReadMemberRecursive(value, memberName);
|
|
||||||
if (nested != null && ContainsAnyToken(SafeLower(nested.ToString())))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static object ReadMemberRecursive(object instance, string name)
|
|
||||||
{
|
|
||||||
if (instance == null || string.IsNullOrWhiteSpace(name))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
Type type = instance.GetType();
|
|
||||||
|
|
||||||
while (type != null)
|
while (type != null)
|
||||||
{
|
{
|
||||||
PropertyInfo prop = AccessTools.Property(type, name);
|
PropertyInfo prop = AccessTools.Property(type, name);
|
||||||
@@ -216,22 +135,61 @@ namespace AbsorbentSoil
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static bool ContainsAnyToken(string text)
|
internal static class SoilHelper
|
||||||
|
{
|
||||||
|
public static bool IsRetainingSoil(Pot pot)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
string soilId = GetSoilId(pot);
|
||||||
|
if (string.IsNullOrWhiteSpace(soilId))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return RetainingSoilTokens.Any(token => text.Contains(token));
|
soilId = soilId.ToLowerInvariant();
|
||||||
|
return soilId.Contains("longlifesoil") || soilId.Contains("extralonglifesoil");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string SafeLower(string value) => value == null ? string.Empty : value.ToLowerInvariant();
|
public static string GetSoilId(Pot pot)
|
||||||
|
{
|
||||||
|
if (pot == null)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
object soilId = ReadMember(pot, "SoilID") ?? ReadMember(pot, "soilID") ?? ReadMember(pot, "SoilId") ?? ReadMember(pot, "soilId");
|
||||||
|
return soilId?.ToString() ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object ReadMember(object instance, string name)
|
||||||
|
{
|
||||||
|
if (instance == null || string.IsNullOrWhiteSpace(name))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Type type = instance.GetType();
|
||||||
|
while (type != null)
|
||||||
|
{
|
||||||
|
PropertyInfo prop = AccessTools.Property(type, name);
|
||||||
|
if (prop != null)
|
||||||
|
{
|
||||||
|
try { return prop.GetValue(instance); } catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldInfo field = AccessTools.Field(type, name);
|
||||||
|
if (field != null)
|
||||||
|
{
|
||||||
|
try { return field.GetValue(instance); } catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
type = type.BaseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPatch(typeof(Pot), "ApplyAdditive")]
|
[HarmonyPatch(typeof(Pot), "ApplyAdditive")]
|
||||||
internal static class Pot_ApplyAdditive_Patch
|
internal static class Pot_ApplyAdditive_Patch
|
||||||
{
|
{
|
||||||
private static bool _suppressCapture;
|
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)
|
public static void Postfix(Pot __instance, AdditiveDefinition __result, string additiveID, bool isInitialApplication)
|
||||||
{
|
{
|
||||||
@@ -259,8 +217,7 @@ namespace AbsorbentSoil
|
|||||||
if (pot == null || string.IsNullOrWhiteSpace(additiveID))
|
if (pot == null || string.IsNullOrWhiteSpace(additiveID))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MethodInfo applyAdditive = AccessTools.Method(typeof(Pot), "ApplyAdditive");
|
if (ApplyAdditiveMethod == null)
|
||||||
if (applyAdditive == null)
|
|
||||||
{
|
{
|
||||||
MelonLogger.Warning("Could not find Pot.ApplyAdditive via reflection.");
|
MelonLogger.Warning("Could not find Pot.ApplyAdditive via reflection.");
|
||||||
return;
|
return;
|
||||||
@@ -269,7 +226,7 @@ namespace AbsorbentSoil
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_suppressCapture = true;
|
_suppressCapture = true;
|
||||||
applyAdditive.Invoke(pot, new object[] { additiveID, true });
|
ApplyAdditiveMethod.Invoke(pot, new object[] { additiveID, true });
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -293,8 +250,12 @@ namespace AbsorbentSoil
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Pot pot = __instance.Pot;
|
Pot pot = __instance.Pot;
|
||||||
|
|
||||||
if (!SoilHelper.IsRetainingSoil(pot))
|
if (!SoilHelper.IsRetainingSoil(pot))
|
||||||
|
{
|
||||||
|
AdditiveMemory.Forget(pot);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IReadOnlyList<string> additiveIds = AdditiveMemory.Get(pot);
|
IReadOnlyList<string> additiveIds = AdditiveMemory.Get(pot);
|
||||||
if (additiveIds.Count == 0)
|
if (additiveIds.Count == 0)
|
||||||
@@ -317,8 +278,20 @@ namespace AbsorbentSoil
|
|||||||
{
|
{
|
||||||
public static void Postfix(Pot __instance)
|
public static void Postfix(Pot __instance)
|
||||||
{
|
{
|
||||||
// Intentionally do nothing. This patch exists as a reminder that retained additives should survive harvest.
|
try
|
||||||
// Do NOT clear AdditiveMemory here, because long-life/extra-long-life soil should carry additives forward.
|
{
|
||||||
|
if (__instance == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// After the game's harvest logic runs, if soil was consumed/removed or is no longer retaining soil,
|
||||||
|
// clear the retained additives so freshly re-poured soil starts clean.
|
||||||
|
if (!SoilHelper.IsRetainingSoil(__instance))
|
||||||
|
AdditiveMemory.Forget(__instance);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MelonLogger.Warning($"OnPlantFullyHarvested postfix failed: {ex}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +300,6 @@ namespace AbsorbentSoil
|
|||||||
{
|
{
|
||||||
public static void Prefix(Pot __instance)
|
public static void Prefix(Pot __instance)
|
||||||
{
|
{
|
||||||
// If the pot itself is destroyed/sold, stop tracking its additives.
|
|
||||||
try { AdditiveMemory.Forget(__instance); }
|
try { AdditiveMemory.Forget(__instance); }
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
Binary file not shown.
@@ -13,7 +13,7 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("AbsorbentSoil")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("AbsorbentSoil")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+1374b2e929263849b9362bc2032e73ac19079563")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("AbsorbentSoil")]
|
[assembly: System.Reflection.AssemblyProductAttribute("AbsorbentSoil")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("AbsorbentSoil")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("AbsorbentSoil")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
54ce364b284ea9f7c7e326b3938578be61e76fb507bfb64c59c1c67e28888f74
|
c2488a0a4e0149be33c85611dadce8edca6655bd5fdedcb3c238565f85b2d0ec
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user