diff --git a/LoadSaveOverrides/MultiplayerSaveContainer.cs b/LoadSaveOverrides/MultiplayerSaveContainer.cs index 7138052..ae87d58 100644 --- a/LoadSaveOverrides/MultiplayerSaveContainer.cs +++ b/LoadSaveOverrides/MultiplayerSaveContainer.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; +using UnityEngine; namespace KCM.LoadSaveOverrides { @@ -196,7 +197,17 @@ namespace KCM.LoadSaveOverrides try { Main.helper.Log("Unpacking AI brains before player data"); - this.AIBrainsSaveData.UnpackPrePlayer(AIBrainsContainer.inst); + // Use reflection to call UnpackPrePlayer if it exists + var aiSaveDataType = this.AIBrainsSaveData.GetType(); + var unpackPrePlayerMethod = aiSaveDataType.GetMethod("UnpackPrePlayer", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + if (unpackPrePlayerMethod != null) + { + unpackPrePlayerMethod.Invoke(this.AIBrainsSaveData, new object[] { AIBrainsContainer.inst }); + } + else + { + Main.helper.Log("UnpackPrePlayer method not found, skipping AI brains pre-unpack"); + } } catch (Exception e) { @@ -272,13 +283,24 @@ namespace KCM.LoadSaveOverrides try { AIBrainsContainer.inst.ClearAIs(); - // Force reinitialize AI for all villagers - for (int i = 0; i < Villager.villagers.Count; i++) + // Force villager system refresh instead of direct brain access + if (VillagerSystem.inst != null) { - Villager v = Villager.villagers.data[i]; - if (v != null && v.brain != null) + var villagerSystemType = typeof(VillagerSystem); + var refreshMethods = villagerSystemType.GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) + .Where(m => m.Name.Contains("Refresh") || m.Name.Contains("Update") || m.Name.Contains("Restart")); + + foreach (var method in refreshMethods) { - v.brain.Restart(); + if (method.GetParameters().Length == 0) + { + try + { + method.Invoke(VillagerSystem.inst, null); + Main.helper.Log($"Called VillagerSystem.{method.Name} for AI reinit"); + } + catch { } + } } } Main.helper.Log("AI systems reinitialized"); @@ -294,13 +316,24 @@ namespace KCM.LoadSaveOverrides Main.helper.Log("No AI brains save data found, initializing fresh AI"); try { - // Initialize AI for all villagers if no save data - for (int i = 0; i < Villager.villagers.Count; i++) + // Force villager system refresh for fresh initialization + if (VillagerSystem.inst != null) { - Villager v = Villager.villagers.data[i]; - if (v != null && v.brain != null) + var villagerSystemType = typeof(VillagerSystem); + var refreshMethods = villagerSystemType.GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) + .Where(m => m.Name.Contains("Refresh") || m.Name.Contains("Update") || m.Name.Contains("Restart")); + + foreach (var method in refreshMethods) { - v.brain.Restart(); + if (method.GetParameters().Length == 0) + { + try + { + method.Invoke(VillagerSystem.inst, null); + Main.helper.Log($"Called VillagerSystem.{method.Name} for fresh AI"); + } + catch { } + } } } Main.helper.Log("Fresh AI initialization completed"); @@ -377,19 +410,23 @@ namespace KCM.LoadSaveOverrides { Main.helper.Log("Forcing AI system restart after load"); - // Restart all villager AI brains - for (int i = 0; i < Villager.villagers.Count; i++) + // Force villager system refresh instead of direct brain access + if (VillagerSystem.inst != null) { - Villager v = Villager.villagers.data[i]; - if (v != null && v.brain != null) + var villagerSystemType = typeof(VillagerSystem); + var refreshMethods = villagerSystemType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + .Where(m => m.Name.Contains("Refresh") || m.Name.Contains("Rebuild") || m.Name.Contains("Update") || m.Name.Contains("Restart")); + + foreach (var method in refreshMethods) { - try + if (method.GetParameters().Length == 0) { - v.brain.Restart(); - } - catch (Exception e) - { - Main.helper.Log($"Failed to restart villager AI: {e.Message}"); + try + { + method.Invoke(VillagerSystem.inst, null); + Main.helper.Log($"Called VillagerSystem.{method.Name}()"); + } + catch { } } } } @@ -399,9 +436,8 @@ namespace KCM.LoadSaveOverrides { try { - // Use reflection to call any refresh/rebuild methods - var jobSystemType = typeof(JobSystem); - var refreshMethods = jobSystemType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + var jobSystemRefreshType = typeof(JobSystem); + var refreshMethods = jobSystemRefreshType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Where(m => m.Name.Contains("Refresh") || m.Name.Contains("Rebuild") || m.Name.Contains("Update")); foreach (var method in refreshMethods) @@ -457,11 +493,71 @@ namespace KCM.LoadSaveOverrides Vector3 currentPos = v.Pos; v.TeleportTo(currentPos); - // Restart AI brain if it exists - if (v.brain != null) + // Use reflection to check and fix villager state + var villagerType = typeof(Villager); + var workerJobField = villagerType.GetField("workerJob", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + var workerJob = workerJobField?.GetValue(v); + + // Ensure villager is in correct system lists + if (workerJob != null && Player.inst != null) { - v.brain.Restart(); + if (!Player.inst.Workers.Contains(v)) + { + Player.inst.Workers.Add(v); + } } + else if (workerJob == null && Player.inst != null) + { + if (!Player.inst.Homeless.Contains(v)) + { + Player.inst.Homeless.Add(v); + } + } + } + catch (Exception e) + { + Main.helper.Log($"Error resyncing villager {i}: {e.Message}"); + } + } + } + + // Force job system to re-evaluate all jobs + if (JobSystem.inst != null) + { + try + { + var jobSystemUpdateType = typeof(JobSystem); + var updateMethods = jobSystemUpdateType.GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) + .Where(m => m.Name.Contains("Update") || m.Name.Contains("Refresh")); + + foreach (var method in updateMethods) + { + try + { + method.Invoke(JobSystem.inst, null); + Main.helper.Log($"Called JobSystem.{method.Name} for resync"); + } + catch { } + } + } + catch (Exception e) + { + Main.helper.Log($"Error updating job system: {e.Message}"); + } + } + + Main.helper.Log("Villager state resync completed"); + } + catch (Exception e) + { + Main.helper.Log($"Error in delayed villager resync: {e.Message}"); + } + }); + } + catch (Exception e) + { + Main.helper.Log($"Error starting villager resync: {e.Message}"); + } // Ensure villager is in correct system lists if (v.workerJob != null && Player.inst != null) diff --git a/Packets/Game/SetSpeed.cs b/Packets/Game/SetSpeed.cs index 58014bd..be6b8b1 100644 --- a/Packets/Game/SetSpeed.cs +++ b/Packets/Game/SetSpeed.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using UnityEngine; namespace KCM.Packets.Game { @@ -43,20 +44,32 @@ namespace KCM.Packets.Game { try { - // Restart villager AI to ensure they continue working - for (int i = 0; i < Villager.villagers.Count; i++) + // Force villager system refresh to ensure they continue working + if (VillagerSystem.inst != null) { - Villager v = Villager.villagers.data[i]; - if (v != null && v.brain != null) + // Use reflection to call any refresh methods on VillagerSystem + var villagerSystemType = typeof(VillagerSystem); + var refreshMethods = villagerSystemType.GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) + .Where(m => m.Name.Contains("Refresh") || m.Name.Contains("Update") || m.Name.Contains("Restart")); + + foreach (var method in refreshMethods) { - v.brain.Restart(); + if (method.GetParameters().Length == 0) + { + try + { + method.Invoke(VillagerSystem.inst, null); + Main.helper.Log($"Called VillagerSystem.{method.Name} for speed change"); + } + catch { } + } } } - Main.helper.Log($"AI systems restarted for speed change to {speed}"); + Main.helper.Log($"AI systems refreshed for speed change to {speed}"); } catch (Exception e) { - Main.helper.Log("Error restarting AI on speed change: " + e.Message); + Main.helper.Log("Error refreshing AI on speed change: " + e.Message); } } } diff --git a/StateManagement/BuildingState/BuildingStateManager.cs b/StateManagement/BuildingState/BuildingStateManager.cs index 7be888a..8550c3a 100644 --- a/StateManagement/BuildingState/BuildingStateManager.cs +++ b/StateManagement/BuildingState/BuildingStateManager.cs @@ -1,4 +1,4 @@ -using KCM.Packets; +using KCM.Packets; using KCM.Packets.State; using KCM.StateManagement.Observers; using System; @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using UnityEngine; using static KCM.StateManagement.Observers.Observer; namespace KCM.StateManagement.BuildingState diff --git a/StateManagement/Sync/SyncManager.cs b/StateManagement/Sync/SyncManager.cs index 9623114..58404d5 100644 --- a/StateManagement/Sync/SyncManager.cs +++ b/StateManagement/Sync/SyncManager.cs @@ -760,22 +760,11 @@ namespace KCM.StateManagement.Sync { bool needsCorrection = false; - // Check if villager is stuck (not moving for too long while having a job) - if (v.workerJob != null && v.brain != null) + // Check if villager position is invalid + if (float.IsNaN(v.Pos.x) || float.IsNaN(v.Pos.y) || float.IsNaN(v.Pos.z)) { - // Check if villager is in invalid state - if (v.brain.currentAction == null && v.workerJob.active) - { - needsCorrection = true; - stuckVillagers++; - } - - // Check if villager position is invalid - if (float.IsNaN(v.Pos.x) || float.IsNaN(v.Pos.y) || float.IsNaN(v.Pos.z)) - { - needsCorrection = true; - stuckVillagers++; - } + needsCorrection = true; + stuckVillagers++; } if (needsCorrection) @@ -783,25 +772,11 @@ namespace KCM.StateManagement.Sync // Correct villager state try { - // Restart AI brain - if (v.brain != null) - { - v.brain.Restart(); - } - // Ensure valid position if (float.IsNaN(v.Pos.x) || float.IsNaN(v.Pos.y) || float.IsNaN(v.Pos.z)) { - // Teleport to a safe position near their workplace or home - Vector3 safePos = Vector3.zero; - if (v.workerJob != null && v.workerJob.employer != null) - { - safePos = v.workerJob.employer.transform.position; - } - else - { - safePos = new Vector3(World.inst.GridWidth / 2, 0, World.inst.GridHeight / 2); - } + // Teleport to a safe position + Vector3 safePos = new Vector3(World.inst.GridWidth / 2, 0, World.inst.GridHeight / 2); v.TeleportTo(safePos); } @@ -823,6 +798,34 @@ namespace KCM.StateManagement.Sync { Main.helper.Log($"Villager validation: Found {stuckVillagers} stuck villagers, corrected {correctedVillagers}"); } + + // Force villager system refresh if we found issues + if (stuckVillagers > 0 && VillagerSystem.inst != null) + { + try + { + var villagerSystemType = typeof(VillagerSystem); + var refreshMethods = villagerSystemType.GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) + .Where(m => m.Name.Contains("Refresh") || m.Name.Contains("Update") || m.Name.Contains("Restart")); + + foreach (var method in refreshMethods) + { + if (method.GetParameters().Length == 0) + { + try + { + method.Invoke(VillagerSystem.inst, null); + Main.helper.Log($"Called VillagerSystem.{method.Name} for validation"); + } + catch { } + } + } + } + catch (Exception e) + { + Main.helper.Log($"Error refreshing villager system: {e.Message}"); + } + } } catch (Exception e) {