Compare commits
5 Commits
0a2c44832f
...
9fbc01e6a4
| Author | SHA1 | Date | |
|---|---|---|---|
| 9fbc01e6a4 | |||
| 5b84511923 | |||
| 4277098e13 | |||
| 11a4660881 | |||
| fb6889e310 |
@@ -1,4 +1,4 @@
|
|||||||
using Harmony;
|
using Harmony;
|
||||||
using KCM.Enums;
|
using KCM.Enums;
|
||||||
using KCM.Packets;
|
using KCM.Packets;
|
||||||
using KCM.Packets.Handlers;
|
using KCM.Packets.Handlers;
|
||||||
@@ -25,12 +25,6 @@ namespace KCM
|
|||||||
|
|
||||||
public static KCClient inst { get; set; }
|
public static KCClient inst { get; set; }
|
||||||
|
|
||||||
|
|
||||||
static KCClient()
|
|
||||||
{
|
|
||||||
InitializeClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void InitializeClient()
|
private static void InitializeClient()
|
||||||
{
|
{
|
||||||
// Clean up old client if exists
|
// Clean up old client if exists
|
||||||
|
|||||||
237
Main.cs
237
Main.cs
@@ -1,4 +1,4 @@
|
|||||||
using Assets.Code;
|
using Assets.Code;
|
||||||
using Assets.Code.UI;
|
using Assets.Code.UI;
|
||||||
using Assets.Interface;
|
using Assets.Interface;
|
||||||
using Harmony;
|
using Harmony;
|
||||||
@@ -49,6 +49,7 @@ namespace KCM
|
|||||||
{
|
{
|
||||||
public class Main : MonoBehaviour
|
public class Main : MonoBehaviour
|
||||||
{
|
{
|
||||||
|
public static Main instance;
|
||||||
public static KCModHelper helper;
|
public static KCModHelper helper;
|
||||||
public static MenuState menuState = (MenuState)MainMenuMode.State.Uninitialized;
|
public static MenuState menuState = (MenuState)MainMenuMode.State.Uninitialized;
|
||||||
|
|
||||||
@@ -229,6 +230,8 @@ namespace KCM
|
|||||||
|
|
||||||
private void Preload(KCModHelper helper)
|
private void Preload(KCModHelper helper)
|
||||||
{
|
{
|
||||||
|
instance = this;
|
||||||
|
|
||||||
helper.Log("Preload start in main");
|
helper.Log("Preload start in main");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -2031,238 +2034,6 @@ namespace KCM
|
|||||||
|
|
||||||
#endregion
|
#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"
|
#region "Unity Log Hooks"
|
||||||
|
|
||||||
[HarmonyPatch(typeof(UnityEngine.Debug), "Log", new Type[] { typeof(object) })]
|
[HarmonyPatch(typeof(UnityEngine.Debug), "Log", new Type[] { typeof(object) })]
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace KCM
|
namespace KCM
|
||||||
{
|
{
|
||||||
public class PrefabManager
|
public class PrefabManager
|
||||||
{
|
{
|
||||||
|
public static KCModHelper helper;
|
||||||
public static AssetBundle assetBundle;
|
public static AssetBundle assetBundle;
|
||||||
public static GameObject serverBrowserPrefab;
|
public static GameObject serverBrowserPrefab;
|
||||||
public static GameObject serverEntryItemPrefab;
|
public static GameObject serverEntryItemPrefab;
|
||||||
@@ -20,42 +18,62 @@ namespace KCM
|
|||||||
|
|
||||||
public static GameObject modalUIPrefab;
|
public static GameObject modalUIPrefab;
|
||||||
|
|
||||||
public void PreScriptLoad(KCModHelper _helper)
|
public static void PreScriptLoad(KCModHelper _helper)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//Main.helper = _helper;
|
if (_helper != null)
|
||||||
|
|
||||||
assetBundle = KCModHelper.LoadAssetBundle(_helper.modPath, "serverbrowserpkg");
|
|
||||||
|
|
||||||
if (assetBundle == null)
|
|
||||||
{
|
{
|
||||||
Main.helper.Log("ERROR: Asset bundle 'serverbrowserpkg' not found! UI features will not work.");
|
helper = _helper;
|
||||||
Main.helper.Log("Please ensure the asset bundle file is in the mod directory.");
|
}
|
||||||
|
else if (Main.helper != null)
|
||||||
|
{
|
||||||
|
helper = Main.helper;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (helper == null)
|
||||||
|
{
|
||||||
|
Debug.Log("KCM: PrefabManager helper is null, cannot proceed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Main.helper.Log("Asset bundle loaded successfully");
|
// LoadAssetBundle is a static method, so we call it on the class, not the instance.
|
||||||
Main.helper.Log("Assets in bundle: " + String.Join(", ", assetBundle.GetAllAssetNames()));
|
// We pass the modPath from the helper instance we have.
|
||||||
|
assetBundle = KCModHelper.LoadAssetBundle(helper.modPath, "serverbrowserpkg");
|
||||||
|
|
||||||
serverBrowserPrefab = assetBundle.LoadAsset("assets/workspace/serverbrowser.prefab") as GameObject;
|
if (assetBundle == null)
|
||||||
serverEntryItemPrefab = assetBundle.LoadAsset("assets/workspace/serverentryitem.prefab") as GameObject;
|
{
|
||||||
|
helper.Log("ERROR: Asset bundle 'serverbrowserpkg' not found! UI features will not work.");
|
||||||
|
helper.Log("Please ensure the asset bundle file is in the mod directory.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
serverLobbyPrefab = assetBundle.LoadAsset("assets/workspace/serverlobby.prefab") as GameObject;
|
helper.Log("Asset bundle loaded successfully");
|
||||||
serverLobbyPlayerEntryPrefab = assetBundle.LoadAsset("assets/workspace/serverlobbyplayerentry.prefab") as GameObject;
|
helper.Log("Assets in bundle: " + String.Join(", ", assetBundle.GetAllAssetNames()));
|
||||||
serverChatEntryPrefab = assetBundle.LoadAsset("assets/workspace/serverchatentry.prefab") as GameObject;
|
|
||||||
serverChatSystemEntryPrefab = assetBundle.LoadAsset("assets/workspace/serverchatsystementry.prefab") as GameObject;
|
|
||||||
|
|
||||||
modalUIPrefab = assetBundle.LoadAsset("assets/workspace/modalui.prefab") as GameObject;
|
serverBrowserPrefab = assetBundle.LoadAsset<GameObject>("assets/workspace/serverbrowser.prefab");
|
||||||
|
serverEntryItemPrefab = assetBundle.LoadAsset<GameObject>("assets/workspace/serverentryitem.prefab");
|
||||||
|
|
||||||
Main.helper.Log("Loaded all UI prefabs successfully");
|
serverLobbyPrefab = assetBundle.LoadAsset<GameObject>("assets/workspace/serverlobby.prefab");
|
||||||
|
serverLobbyPlayerEntryPrefab = assetBundle.LoadAsset<GameObject>("assets/workspace/serverlobbyplayerentry.prefab");
|
||||||
|
serverChatEntryPrefab = assetBundle.LoadAsset<GameObject>("assets/workspace/serverchatentry.prefab");
|
||||||
|
serverChatSystemEntryPrefab = assetBundle.LoadAsset<GameObject>("assets/workspace/serverchatsystementry.prefab");
|
||||||
|
|
||||||
|
modalUIPrefab = assetBundle.LoadAsset<GameObject>("assets/workspace/modalui.prefab");
|
||||||
|
|
||||||
|
helper.Log("Loaded all UI prefabs successfully");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Main.helper.Log("ERROR loading asset bundle:");
|
if (helper != null)
|
||||||
Main.helper.Log(ex.ToString());
|
{
|
||||||
Main.helper.Log(ex.Message);
|
helper.Log("ERROR loading asset bundle:");
|
||||||
Main.helper.Log(ex.StackTrace);
|
helper.Log(ex.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Log("ERROR in PrefabManager.PreScriptLoad, helper is null: " + ex.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using KCM;
|
using KCM;
|
||||||
using KCM.Enums;
|
using KCM.Enums;
|
||||||
using KCM.Packets.Handlers;
|
using KCM.Packets.Handlers;
|
||||||
using Steamworks;
|
using Steamworks;
|
||||||
@@ -176,7 +176,7 @@ namespace Riptide.Demos.Steam.PlayerHosted
|
|||||||
// Transition back to server browser
|
// Transition back to server browser
|
||||||
Main.TransitionTo(MenuState.ServerBrowser);
|
Main.TransitionTo(MenuState.ServerBrowser);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (System.Exception ex)
|
||||||
{
|
{
|
||||||
Main.helper.Log("Error during LeaveLobby:");
|
Main.helper.Log("Error during LeaveLobby:");
|
||||||
Main.helper.Log(ex.Message);
|
Main.helper.Log(ex.Message);
|
||||||
|
|||||||
Reference in New Issue
Block a user