Refactor helper assignment in PrefabManager to use Main.helper

This commit is contained in:
2025-12-14 21:55:46 +01:00
parent 5b84511923
commit 9fbc01e6a4
2 changed files with 5 additions and 237 deletions

238
Main.cs
View File

@@ -1,4 +1,4 @@
using Assets.Code;
using Assets.Code;
using Assets.Code.UI;
using Assets.Interface;
using Harmony;
@@ -1154,7 +1154,7 @@ namespace KCM
return false;
}
__result = Application.persistentDataPath + "/Saves"; ;
__result = Application.persistentDataPath + "/Saves"; ;
return true;
}
}
@@ -2034,238 +2034,6 @@ namespace KCM
#endregion
/**
*
* Find all Player.inst references and reconstruct method with references to client planyer
*
* Instantiating main player object and setting landmass teamid in KCPLayer
*
* E.G instead of Player.inst, it should be Main.kCPlayers[Client].player for example, and the rest of the code is the same
*
* Prefix that sets Player.inst to the right client instance and then calls that instances method?
*
*/
[HarmonyPatch]
public class PlayerReferencePatch
{
static IEnumerable<MethodBase> TargetMethods()
{
Assembly assembly = typeof(Player).Assembly;
Type[] types = new Type[] { typeof(Player)/*, typeof(World), typeof(LandmassOwner), typeof(Keep), typeof(Villager), typeof(DragonSpawn), typeof(DragonController), typeof(Dragon)*/ };
var methodsInNamespace = types
.SelectMany(t => t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(m => !m.IsAbstract))
.ToList();
helper.Log("Methods in namespace: " + methodsInNamespace.Count);
return methodsInNamespace.ToArray().Cast<MethodBase>();
}
static IEnumerable<CodeInstruction> Transpiler(MethodBase method, IEnumerable<CodeInstruction> instructions)
{
int PlayerInstCount = 0;
var codes = new List<CodeInstruction>(instructions);
for (var i = 0; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Ldsfld && codes[i].operand.ToString() == "Player inst")
{
PlayerInstCount++;
codes[i].opcode = (OpCodes.Ldarg_0); // Replace all instance methods static ref with "this" instead of Player.inst
// Replace ldsfld Player::inst with the sequence to load from Main.kCPlayers
// Step 1: Load Main.kCPlayers onto the evaluation stack.
//codes[i] = new CodeInstruction(OpCodes.Ldsfld, typeof(Main).GetField("kCPlayers"));
// Step 2: Load the value of Main.PlayerSteamID onto the evaluation stack as the key
//codes.Insert(++i, new CodeInstruction(OpCodes.Ldsfld, typeof(Main).GetField("PlayerSteamID")));
// Step 3: Call Dictionary<TKey, TValue>.get_Item(TKey key) to get the Player instance.
//codes.Insert(++i, new CodeInstruction(OpCodes.Callvirt, typeof(Dictionary<string, KCPlayer>).GetMethod("get_Item")));
// Now, access the 'inst' field of the fetched Player instance, if necessary.
//codes.Insert(++i, new CodeInstruction(OpCodes.Ldfld, typeof(KCPlayer).GetField("inst")));
}
}
if (PlayerInstCount > 0)
Main.helper.Log($"Found {PlayerInstCount} static Player.inst references in {method.Name}");
return codes.AsEnumerable();
}
}
[HarmonyPatch]
public class BuildingPlayerReferencePatch
{
static IEnumerable<MethodBase> TargetMethods()
{
Assembly assembly = typeof(Building).Assembly;
Type[] types = new Type[] { typeof(Building) };
var methodsInNamespace = types
.SelectMany(t => t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(m => !m.IsAbstract))
.ToList();
helper.Log("Methods in namespace: " + methodsInNamespace.Count);
return methodsInNamespace.ToArray().Cast<MethodBase>();
}
static IEnumerable<CodeInstruction> Transpiler(MethodBase method, IEnumerable<CodeInstruction> instructions)
{
int PlayerInstCount = 0;
var codes = new List<CodeInstruction>(instructions);
MethodInfo getPlayerByBuildingMethodInfo = typeof(Main).GetMethod("GetPlayerByBuilding", BindingFlags.Static | BindingFlags.Public);
for (var i = 0; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Ldsfld && codes[i].operand.ToString() == "Player inst")
{
PlayerInstCount++;
// Check if the current instruction is ldsfld Player.inst
if (codes[i].opcode == OpCodes.Ldsfld && codes[i].operand.ToString().Contains("Player inst"))
{
// Replace the instruction sequence
// Step 1: Load 'this' for the Building instance
codes[i].opcode = OpCodes.Ldarg_0;
// Step 2: Call GetPlayerByBuilding(Building instance) static method in Main
var callTeamID = new CodeInstruction(OpCodes.Call, getPlayerByBuildingMethodInfo);
codes.Insert(++i, callTeamID);
}
}
}
if (PlayerInstCount > 0)
Main.helper.Log($"Found {PlayerInstCount} static building Player.inst references in {method.Name}");
return codes.AsEnumerable();
}
}
[HarmonyPatch]
public class PlayerPatch
{
static IEnumerable<MethodBase> TargetMethods()
{
var meth = typeof(Player).GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
return meth.Cast<MethodBase>();
}
public static bool Prefix(MethodBase __originalMethod, Player __instance)
{
if (__originalMethod.Name.Equals("Awake") && (KCServer.IsRunning || KCClient.client.IsConnected))
{
helper.Log("Awake run on player instance while server is running");
return false;
}
if (__originalMethod.Name.Equals("Awake") && __instance.gameObject.name.Contains("Client Player"))
{
helper.Log("Awake run on client instance");
try
{
//___defaultEnabledFlags = new bool[38];
//for (int i = 0; i < ___defaultEnabledFlags.Length; i++)
//{
// ___defaultEnabledFlags[i] = true;
//}
//__instance.PlayerLandmassOwner = __instance.gameObject.AddComponent<LandmassOwner>();
//helper.Log(__instance.PlayerLandmassOwner.ToString());
}
catch (Exception e)
{
helper.Log(e.ToString());
helper.Log(e.Message);
helper.Log(e.StackTrace);
}
return false;
}
if (__originalMethod.Name.Equals("Update") && __instance.gameObject.name.Contains("Client Player"))
{
//helper.Log("Update run on client instance");
try
{
//___defaultEnabledFlags = new bool[38];
//for (int i = 0; i < ___defaultEnabledFlags.Length; i++)
//{
// ___defaultEnabledFlags[i] = true;
//}
//__instance.PlayerLandmassOwner = __instance.gameObject.AddComponent<LandmassOwner>();
//helper.Log(__instance.PlayerLandmassOwner.ToString());
}
catch (Exception e)
{
helper.Log(e.ToString());
helper.Log(e.Message);
helper.Log(e.StackTrace);
}
return false;
}
if (__originalMethod.Name.Equals("Update"))
{
//helper.Log($"Update called for: {__instance.gameObject.name}");
try
{
if (KCClient.client.IsConnected && !__instance.gameObject.name.Contains("Client Player"))
{
StateObserver.RegisterObserver(__instance, new string[] {
"bannerIdx", "kingdomHappiness", "landMassHappiness", "landMassIntegrity", "bDidFirstFire", "CurrYear",
"timeAtFailHappiness", "hasUsedCheats", "nameForOldAgeDeath", "deathsThisYear", /*"poorHealthGracePeriod",*/
});
//StateObserver.Update(__instance);
}
}
catch (Exception e)
{
helper.Log(e.ToString());
helper.Log(e.Message);
helper.Log(e.StackTrace);
}
return true;
}
return true;
}
public static void Postfix(MethodBase __originalMethod, Player __instance)
{
if (__originalMethod.Name.Equals("Update"))
{
//helper.Log($"Update called for: {__instance.gameObject.name} in POSTFIX");
//helper.Log("CHECKING ALL COMPONENTS IN UPDATE: ");
//Component[] components = __instance.gameObject.GetComponents<Component>();
//foreach (Component component in components)
//{
// helper.Log("--- " + component.GetType().kingdomName);
//}
}
}
}
#region "Unity Log Hooks"
[HarmonyPatch(typeof(UnityEngine.Debug), "Log", new Type[] { typeof(object) })]
@@ -2415,4 +2183,4 @@ namespace KCM
}
}
}
}

View File

@@ -26,9 +26,9 @@ namespace KCM
{
helper = _helper;
}
else if (Main.instance != null)
else if (Main.helper != null)
{
helper = Main.instance.helper;
helper = Main.helper;
}
if (helper == null)