From f03e13236f0024badc32ae5f961e9dda7042da88 Mon Sep 17 00:00:00 2001 From: devbeni Date: Sun, 14 Dec 2025 01:45:02 +0100 Subject: [PATCH] asd --- Attributes/NoServerRelayAttribute.cs | 10 - Enums/Packets.cs | 6 +- KCClient.cs | 17 +- KCServer.cs | 106 +- LoadSaveOverrides/MultiplayerSaveContainer.cs | 151 +-- Main.cs | 905 ++---------------- .../GameVillager/VillagerSnapshotPacket.cs | 56 -- Packets/Game/SetSpeed.cs | 19 +- Packets/Handlers/LobbyHandler.cs | 1 - Packets/Handlers/PacketHandler.cs | 79 +- Packets/Lobby/PlayerList.cs | 19 +- Packets/Lobby/PlayerReady.cs | 4 - Packets/Lobby/SaveTransferPacket.cs | 94 +- Packets/Lobby/StartGame.cs | 4 +- Packets/Lobby/WorldSeed.cs | 8 - Packets/Network/ClientConnected.cs | 45 +- Packets/Network/ResyncRequestPacket.cs | 35 - Packets/Network/ServerHandshake.cs | 3 +- Packets/Packet.cs | 18 +- Packets/State/BuildingSnapshotPacket.cs | 33 - Packets/State/BuildingStatePacket.cs | 1 - Packets/State/ResourceSnapshotPacket.cs | 37 - RiptideSteamTransport/LobbyManager.cs | 16 +- ServerLobby/LobbyChat/ChatEntryScript.cs | 20 +- ServerLobby/PlayerEntryScript.cs | 43 +- ServerLobby/ServerLobbyScript.cs | 17 +- .../BuildingState/BuildingStateManager.cs | 60 +- StateManagement/Observers/Observer.cs | 25 - StateManagement/Observers/StateObserver.cs | 18 - StateManagement/Sync/SyncManager.cs | 890 ----------------- 30 files changed, 260 insertions(+), 2480 deletions(-) delete mode 100644 Attributes/NoServerRelayAttribute.cs delete mode 100644 Packets/Game/GameVillager/VillagerSnapshotPacket.cs delete mode 100644 Packets/Network/ResyncRequestPacket.cs delete mode 100644 Packets/State/BuildingSnapshotPacket.cs delete mode 100644 Packets/State/ResourceSnapshotPacket.cs delete mode 100644 StateManagement/Sync/SyncManager.cs diff --git a/Attributes/NoServerRelayAttribute.cs b/Attributes/NoServerRelayAttribute.cs deleted file mode 100644 index df2e6a8..0000000 --- a/Attributes/NoServerRelayAttribute.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace KCM.Attributes -{ - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] - public class NoServerRelayAttribute : Attribute - { - } -} - diff --git a/Enums/Packets.cs b/Enums/Packets.cs index bc68b8c..f7da401 100644 --- a/Enums/Packets.cs +++ b/Enums/Packets.cs @@ -44,10 +44,6 @@ namespace KCM.Enums AddVillager = 88, SetupInitialWorkers = 89, VillagerTeleportTo = 90, - PlaceKeepRandomly = 91, - ResyncRequest = 92, - ResourceSnapshot = 93, - BuildingSnapshot = 94, - VillagerSnapshot = 95 + PlaceKeepRandomly = 91 } } diff --git a/KCClient.cs b/KCClient.cs index d81a7d4..fa52f44 100644 --- a/KCClient.cs +++ b/KCClient.cs @@ -39,8 +39,6 @@ namespace KCM Main.helper.Log("Client disconnected event start"); try { - Main.ResetMultiplayerState("Client disconnected"); - if (e.Message != null) { Main.helper.Log(e.Message.ToString()); @@ -78,19 +76,7 @@ namespace KCM private static void Client_Connected(object sender, EventArgs e) { - try - { - if (client != null && client.Connection != null) - { - client.Connection.CanQualityDisconnect = false; - client.Connection.MaxSendAttempts = 50; - } - } - catch (Exception ex) - { - Main.helper.Log("Error configuring client connection"); - Main.helper.Log(ex.ToString()); - } + } @@ -102,7 +88,6 @@ namespace KCM public static void Connect(string ip) { Main.helper.Log("Trying to connect to: " + ip); - try { Application.runInBackground = true; } catch { } client.Connect(ip, useMessageHandlers: false); } diff --git a/KCServer.cs b/KCServer.cs index 685f347..0648689 100644 --- a/KCServer.cs +++ b/KCServer.cs @@ -21,9 +21,6 @@ namespace KCM public static Server server = new Server(Main.steamServer); public static bool started = false; - private static readonly Dictionary> saveTransferQueues = new Dictionary>(); - private const int SaveTransferPacketsPerUpdatePerClient = 10; - static KCServer() { //server.registerMessageHandler(typeof(KCServer).GetMethod("ClientJoined")); @@ -53,7 +50,6 @@ namespace KCM } ev.Client.CanQualityDisconnect = false; - ev.Client.MaxSendAttempts = 50; Main.helper.Log("Client ID is: " + ev.Client.Id); @@ -62,42 +58,15 @@ namespace KCM server.ClientDisconnected += (obj, ev) => { - try + new ChatSystemMessage() { - var playerName = $"Client {ev.Client.Id}"; - string steamId; - if (Main.clientSteamIds.TryGetValue(ev.Client.Id, out steamId) && !string.IsNullOrEmpty(steamId)) - { - KCPlayer player; - if (Main.kCPlayers.TryGetValue(steamId, out player) && player != null && !string.IsNullOrEmpty(player.name)) - playerName = player.name; + Message = $"{Main.GetPlayerByClientID(ev.Client.Id).name} has left the server.", + }.SendToAll(); - Main.kCPlayers.Remove(steamId); - } + Main.kCPlayers.Remove(Main.GetPlayerByClientID(ev.Client.Id).steamId); + Destroy(LobbyHandler.playerEntries.Select(x => x.GetComponent()).Where(x => x.Client == ev.Client.Id).FirstOrDefault().gameObject); - Main.clientSteamIds.Remove(ev.Client.Id); - - new ChatSystemMessage() - { - Message = $"{playerName} has left the server.", - }.SendToAll(); - - var entry = LobbyHandler.playerEntries - .Select(x => x != null ? x.GetComponent() : null) - .FirstOrDefault(x => x != null && x.Client == ev.Client.Id); - - if (entry != null) - Destroy(entry.gameObject); - - saveTransferQueues.Remove(ev.Client.Id); - - Main.helper.Log($"Client disconnected. {ev.Reason}"); - } - catch (Exception ex) - { - Main.helper.Log("Error handling client disconnect"); - Main.helper.Log(ex.ToString()); - } + Main.helper.Log($"Client disconnected. {ev.Reason}"); }; Main.helper.Log($"Listening on port 7777. Max {LobbyHandler.ServerSettings.MaxPlayers} clients."); @@ -131,69 +100,6 @@ namespace KCM private void Update() { server.Update(); - ProcessSaveTransfers(); - KCM.StateManagement.Sync.SyncManager.ServerUpdate(); - } - - private static void ProcessSaveTransfers() - { - if (!KCServer.IsRunning) - return; - - if (saveTransferQueues.Count == 0) - return; - - var clients = saveTransferQueues.Keys.ToList(); - foreach (var clientId in clients) - { - Queue queue; - if (!saveTransferQueues.TryGetValue(clientId, out queue) || queue == null) - continue; - - int sentThisUpdate = 0; - while (sentThisUpdate < SaveTransferPacketsPerUpdatePerClient && queue.Count > 0) - { - var packet = queue.Dequeue(); - packet.Send(clientId); - sentThisUpdate++; - } - - if (queue.Count == 0) - saveTransferQueues.Remove(clientId); - } - } - - public static void EnqueueSaveTransfer(ushort toClient, byte[] bytes) - { - if (bytes == null) - return; - - int chunkSize = 900; - int sent = 0; - int totalChunks = (int)Math.Ceiling((double)bytes.Length / chunkSize); - - var queue = new Queue(totalChunks); - for (int i = 0; i < totalChunks; i++) - { - int currentChunkSize = Math.Min(chunkSize, bytes.Length - sent); - var chunk = new byte[currentChunkSize]; - Array.Copy(bytes, sent, chunk, 0, currentChunkSize); - - queue.Enqueue(new SaveTransferPacket() - { - saveSize = bytes.Length, - saveDataChunk = chunk, - chunkId = i, - chunkSize = chunk.Length, - saveDataIndex = sent, - totalChunks = totalChunks - }); - - sent += currentChunkSize; - } - - saveTransferQueues[toClient] = queue; - Main.helper.Log($"Queued {totalChunks} save data chunks for client {toClient}"); } private void OnApplicationQuit() diff --git a/LoadSaveOverrides/MultiplayerSaveContainer.cs b/LoadSaveOverrides/MultiplayerSaveContainer.cs index 8e3a963..918f003 100644 --- a/LoadSaveOverrides/MultiplayerSaveContainer.cs +++ b/LoadSaveOverrides/MultiplayerSaveContainer.cs @@ -1,4 +1,4 @@ -using Assets.Code; +using Assets.Code; using Riptide; using Riptide.Transports; using Steamworks; @@ -8,7 +8,6 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; -using UnityEngine; namespace KCM.LoadSaveOverrides { @@ -25,41 +24,15 @@ namespace KCM.LoadSaveOverrides Main.helper.Log($"Saving data for {Main.kCPlayers.Count} ({KCServer.server.ClientCount}) players."); + //this.PlayerSaveData = new PlayerSaveDataOverride().Pack(Player.inst); foreach (var player in Main.kCPlayers.Values) { - try - { - if (player == null) - continue; + Main.helper.Log($"Attempting to pack data for: " + player.name + $"({player.steamId})"); + Main.helper.Log($"{player.inst.ToString()} {player.inst?.gameObject.name}"); + this.players.Add(player.steamId, new Player.PlayerSaveData().Pack(player.inst)); + kingdomNames.Add(player.steamId, player.kingdomName); - if (string.IsNullOrWhiteSpace(player.steamId)) - { - Main.helper.Log($"Skipping save for player with missing steamId (name={player.name ?? string.Empty})"); - continue; - } - - if (player.inst == null) - { - Main.helper.Log($"Skipping save for player {player.name ?? string.Empty} ({player.steamId}) because Player.inst is null"); - continue; - } - - Main.helper.Log($"Attempting to pack data for: {player.name} ({player.steamId})"); - string playerGoName = (player.inst.gameObject != null) ? player.inst.gameObject.name : string.Empty; - Main.helper.Log($"Player object: {player.inst} {playerGoName}"); - - this.players[player.steamId] = new Player.PlayerSaveData().Pack(player.inst); - kingdomNames[player.steamId] = player.kingdomName ?? " "; - - Main.helper.Log($"{players[player.steamId] == null}"); - } - catch (Exception ex) - { - string steamId = (player != null && player.steamId != null) ? player.steamId : string.Empty; - string name = (player != null && player.name != null) ? player.name : string.Empty; - Main.helper.Log($"Error packing player data for save (steamId={steamId}, name={name})"); - Main.helper.Log(ex.ToString()); - } + Main.helper.Log($"{players[player.steamId] == null}"); } this.WorldSaveData = new World.WorldSaveData().Pack(World.inst); @@ -71,25 +44,7 @@ namespace KCM.LoadSaveOverrides this.DragonSpawnSaveData = new DragonSpawn.DragonSpawnSaveData().Pack(DragonSpawn.inst); this.UnitSystemSaveData = new UnitSystem.UnitSystemSaveData().Pack(UnitSystem.inst); this.RaidSystemSaveData2 = new RaiderSystem.RaiderSystemSaveData2().Pack(RaiderSystem.inst); - - if (ShipSystem.inst != null) - { - try - { - this.ShipSystemSaveData = new ShipSystem.ShipSystemSaveData().Pack(ShipSystem.inst); - } - catch (Exception ex) - { - Main.helper.Log("Error packing ShipSystem for save; skipping ShipSystemSaveData."); - Main.helper.Log(ex.ToString()); - this.ShipSystemSaveData = null; - } - } - else - { - this.ShipSystemSaveData = null; - } - + this.ShipSystemSaveData = new ShipSystem.ShipSystemSaveData().Pack(ShipSystem.inst); this.AIBrainsSaveData = new AIBrainsContainer.SaveData().Pack(AIBrainsContainer.inst); this.SiegeMonsterSaveData = new SiegeMonster.SiegeMonsterSaveData().Pack(null); this.CartSystemSaveData = new CartSystem.CartSystemSaveData().Pack(CartSystem.inst); @@ -102,8 +57,10 @@ namespace KCM.LoadSaveOverrides public override object Unpack(object obj) { + //original Player reset was up here foreach (var kvp in players) { + KCPlayer player; if (!Main.kCPlayers.TryGetValue(kvp.Key, out player)) @@ -118,6 +75,7 @@ namespace KCM.LoadSaveOverrides foreach (var player in Main.kCPlayers.Values) player.inst.Reset(); + AIBrainsContainer.inst.ClearAIs(); this.CameraSaveData.Unpack(Cam.inst); this.WorldSaveData.Unpack(World.inst); @@ -129,6 +87,10 @@ namespace KCM.LoadSaveOverrides } this.TownNameSaveData.Unpack(TownNameUI.inst); + + //TownNameUI.inst.townName = kingdomNames[Main.PlayerSteamID]; + TownNameUI.inst.SetTownName(kingdomNames[Main.PlayerSteamID]); + Main.helper.Log("Unpacking player data"); Player.PlayerSaveData clientPlayerData = null; @@ -142,9 +104,10 @@ namespace KCM.LoadSaveOverrides clientPlayerData = kvp.Value; } else - { + { // Maybe ?? Main.helper.Log("Loading player data: " + kvp.Key); + KCPlayer player; if (!Main.kCPlayers.TryGetValue(kvp.Key, out player)) @@ -157,63 +120,39 @@ namespace KCM.LoadSaveOverrides Player.inst = player.inst; Main.helper.Log($"Number of landmasses: {World.inst.NumLandMasses}"); + //Reset was here before unpack kvp.Value.Unpack(player.inst); Player.inst = oldPlayer; + player.banner = player.inst.PlayerLandmassOwner.bannerIdx; player.kingdomName = TownNameUI.inst.townName; } } - clientPlayerData.Unpack(Player.inst); + clientPlayerData.Unpack(Player.inst); // Unpack the current client player last so that loading of villagers works correctly. Main.helper.Log("unpacked player data"); Main.helper.Log("Setting banner and name"); var client = Main.kCPlayers[SteamUser.GetSteamID().ToString()]; + client.banner = Player.inst.PlayerLandmassOwner.bannerIdx; client.kingdomName = TownNameUI.inst.townName; Main.helper.Log("Finished unpacking player data"); - Main.helper.Log("Unpacking AI brains"); - bool flag10 = this.AIBrainsSaveData != null; - if (flag10) + /* + * Not even going to bother fixing AI brains save data yet, not in short-term roadmap + */ + + /*bool flag2 = this.AIBrainsSaveData != null; + if (flag2) { - try - { - this.AIBrainsSaveData.Unpack(AIBrainsContainer.inst); - Main.helper.Log("AI brains unpacked successfully"); - } - catch (Exception e) - { - Main.helper.Log("Error unpacking AI brains: " + e.Message); - Main.helper.Log("Attempting to reinitialize AI systems"); - try - { - AIBrainsContainer.inst.ClearAIs(); - Main.helper.Log("AI systems reinitialized"); - } - catch (Exception ex) - { - Main.helper.Log("Failed to reinitialize AI systems: " + ex.Message); - } - } - } - else - { - Main.helper.Log("No AI brains save data found, initializing fresh AI"); - try - { - Main.helper.Log("Fresh AI initialization completed"); - } - catch (Exception e) - { - Main.helper.Log("Failed fresh AI initialization: " + e.Message); - } - } + this.AIBrainsSaveData.UnpackPrePlayer(AIBrainsContainer.inst); + }*/ Main.helper.Log("Unpacking free resource manager"); this.FreeResourceManagerSaveData.Unpack(FreeResourceManager.inst); @@ -268,6 +207,7 @@ namespace KCM.LoadSaveOverrides this.OrdersManagerSaveData.Unpack(OrdersManager.inst); } Main.helper.Log("Unpacking AI brains"); + bool flag10 = this.AIBrainsSaveData != null; if (flag10) { this.AIBrainsSaveData.Unpack(AIBrainsContainer.inst); @@ -280,19 +220,6 @@ namespace KCM.LoadSaveOverrides } Main.helper.Log("Unpacking done"); - try - { - Main.helper.Log("Post-load: rebuilding path costs + villager grid"); - try { World.inst.SetupInitialPathCosts(); } catch (Exception e) { Main.helper.Log(e.ToString()); } - try { World.inst.RebuildVillagerGrid(); } catch (Exception e) { Main.helper.Log(e.ToString()); } - try { Player.inst.irrigation.UpdateIrrigation(); } catch (Exception e) { Main.helper.Log(e.ToString()); } - try { Player.inst.CalcMaxResources(null, -1); } catch (Exception e) { Main.helper.Log(e.ToString()); } - } - catch (Exception e) - { - Main.helper.Log("Post-load rebuild failed"); - Main.helper.Log(e.ToString()); - } World.inst.UpscaleFeatures(); Player.inst.RefreshVisibility(true); @@ -301,32 +228,28 @@ namespace KCM.LoadSaveOverrides Player.inst.Buildings.data[i].UpdateMaterialSelection(); } + // Player.inst.loadTickDelay = 1; Type playerType = typeof(Player); FieldInfo loadTickDelayField = playerType.GetField("loadTickDelay", BindingFlags.Instance | BindingFlags.NonPublic); if (loadTickDelayField != null) { - loadTickDelayField.SetValue(Player.inst, 3); + loadTickDelayField.SetValue(Player.inst, 1); } + // UnitSystem.inst.loadTickDelay = 1; Type unitSystemType = typeof(UnitSystem); loadTickDelayField = unitSystemType.GetField("loadTickDelay", BindingFlags.Instance | BindingFlags.NonPublic); if (loadTickDelayField != null) { - loadTickDelayField.SetValue(UnitSystem.inst, 3); + loadTickDelayField.SetValue(UnitSystem.inst, 1); } + // JobSystem.inst.loadTickDelay = 1; Type jobSystemType = typeof(JobSystem); loadTickDelayField = jobSystemType.GetField("loadTickDelay", BindingFlags.Instance | BindingFlags.NonPublic); if (loadTickDelayField != null) { - loadTickDelayField.SetValue(JobSystem.inst, 3); - } - - Type villagerSystemType = typeof(VillagerSystem); - loadTickDelayField = villagerSystemType.GetField("loadTickDelay", BindingFlags.Instance | BindingFlags.NonPublic); - if (loadTickDelayField != null) - { - loadTickDelayField.SetValue(VillagerSystem.inst, 3); + loadTickDelayField.SetValue(JobSystem.inst, 1); } Main.helper.Log($"Setting kingdom name to: {kingdomNames[Main.PlayerSteamID]}"); @@ -335,4 +258,4 @@ namespace KCM.LoadSaveOverrides return obj; } } -} \ No newline at end of file +} diff --git a/Main.cs b/Main.cs index 86ab564..f574754 100644 --- a/Main.cs +++ b/Main.cs @@ -55,389 +55,30 @@ namespace KCM public static Dictionary kCPlayers = new Dictionary(); public static Dictionary clientSteamIds = new Dictionary(); - private static readonly Dictionary lastTeamIdLookupLogMs = new Dictionary(); - private static int resetInProgress = 0; - private static int multiplayerSaveLoadInProgress = 0; - private static int suppressVillagerTeleportPackets = 0; - - public static bool IsMultiplayerSaveLoadInProgress - { - get { return Volatile.Read(ref multiplayerSaveLoadInProgress) != 0; } - } - - public static void SetMultiplayerSaveLoadInProgress(bool inProgress) - { - Interlocked.Exchange(ref multiplayerSaveLoadInProgress, inProgress ? 1 : 0); - } - - private static bool ShouldSuppressVillagerTeleportPackets - { - get { return Volatile.Read(ref suppressVillagerTeleportPackets) != 0; } - } - - private static void SetSuppressVillagerTeleportPackets(bool suppress) - { - Interlocked.Exchange(ref suppressVillagerTeleportPackets, suppress ? 1 : 0); - } - - public static void ResetMultiplayerState(string reason = null) - { - if (Interlocked.Exchange(ref resetInProgress, 1) == 1) - return; - - try - { - if (!string.IsNullOrEmpty(reason)) - helper?.Log($"ResetMultiplayerState: {reason}"); - - try { StateObserver.ClearAll(); } catch { } - try { SaveTransferPacket.ResetTransferState(); } catch { } - - try - { - LoadSaveLoadHook.memoryStreamHook = false; - LoadSaveLoadHook.saveBytes = new byte[0]; - LoadSaveLoadHook.saveContainer = null; - } - catch { } - - try { LoadSaveLoadAtPathHook.saveData = new byte[0]; } catch { } - - try { LobbyManager.loadingSave = false; } catch { } - try { SetMultiplayerSaveLoadInProgress(false); } catch { } - try { Interlocked.Exchange(ref worldReadyRebuildDone, 0); } catch { } - - try - { - foreach (var player in kCPlayers.Values) - { - if (player?.gameObject != null && player.gameObject.name != null && player.gameObject.name.Contains("Client Player")) - UnityEngine.Object.Destroy(player.gameObject); - } - } - catch { } - - try { LobbyHandler.ClearChatEntries(); } catch { } - try { LobbyHandler.ClearPlayerList(); } catch { } - - try - { - kCPlayers.Clear(); - clientSteamIds.Clear(); - } - catch { } - - try { lastTeamIdLookupLogMs.Clear(); } catch { } - - try - { - if (KCClient.client != null && KCClient.client.IsConnected) - KCClient.client.Disconnect(); - } - catch { } - - try - { - if (KCServer.IsRunning) - KCServer.server.Stop(); - } - catch { } - - try { ServerBrowser.registerServer = false; } catch { } - } - finally - { - Interlocked.Exchange(ref resetInProgress, 0); - } - } - public static KCPlayer GetPlayerByClientID(ushort clientId) { return kCPlayers[clientSteamIds[clientId]]; } - private static void SetLoadTickDelay(object instance, int ticks) - { - if (instance == null) - return; - - try - { - FieldInfo loadTickDelayField = instance.GetType().GetField("loadTickDelay", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - if (loadTickDelayField != null) - { - loadTickDelayField.SetValue(instance, ticks); - return; - } - - PropertyInfo loadTickDelayProp = instance.GetType().GetProperty("loadTickDelay", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - if (loadTickDelayProp != null && loadTickDelayProp.CanWrite && loadTickDelayProp.PropertyType == typeof(int)) - { - loadTickDelayProp.SetValue(instance, ticks, null); - return; - } - - // Debug: list all fields if loadTickDelay not found - if (instance.GetType().Name == "VillagerSystem") - { - helper?.Log("DEBUG: VillagerSystem fields:"); - foreach (var field in instance.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) - { - if (field.FieldType == typeof(int) || field.FieldType == typeof(bool)) - helper?.Log($" Field: {field.Name} ({field.FieldType.Name})"); - } - helper?.Log("DEBUG: VillagerSystem properties:"); - foreach (var prop in instance.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) - { - if (prop.PropertyType == typeof(int) || prop.PropertyType == typeof(bool)) - helper?.Log($" Property: {prop.Name} ({prop.PropertyType.Name})"); - } - } - } - catch (Exception e) - { - helper?.Log("SetLoadTickDelay failed for " + instance.GetType().Name + ": " + e.Message); - } - } - - private static int GetLoadTickDelayOrMinusOne(object instance) - { - if (instance == null) - return -1; - - try - { - FieldInfo loadTickDelayField = instance.GetType().GetField("loadTickDelay", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - if (loadTickDelayField != null) - { - object v = loadTickDelayField.GetValue(instance); - if (v is int) - return (int)v; - } - - PropertyInfo loadTickDelayProp = instance.GetType().GetProperty("loadTickDelay", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - if (loadTickDelayProp != null && loadTickDelayProp.CanRead && loadTickDelayProp.PropertyType == typeof(int)) - { - object pv = loadTickDelayProp.GetValue(instance, null); - if (pv is int) - return (int)pv; - } - } - catch - { - } - - return -1; - } - - private static string TryGetGameModeName() - { - try - { - if (GameState.inst == null) - return "null"; - - var t = GameState.inst.GetType(); - - var modeProp = t.GetProperty("mode", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - ?? t.GetProperty("Mode", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - ?? t.GetProperty("CurrentMode", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - - if (modeProp != null) - { - object m = modeProp.GetValue(GameState.inst, null); - return m != null ? m.GetType().Name : "null"; - } - - var modeField = t.GetField("mode", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - ?? t.GetField("Mode", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - ?? t.GetField("currentMode", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - ?? t.GetField("currMode", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - - if (modeField != null) - { - object fm = modeField.GetValue(GameState.inst); - return fm != null ? fm.GetType().Name : "null"; - } - } - catch - { - } - - return "unknown"; - } - - private static bool TryGetVillagerPosition(Villager villager, out Vector3 position) - { - position = Vector3.zero; - if (villager == null) - return false; - - try - { - var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; - Type type = villager.GetType(); - - string[] gameObjectNames = new string[] { "gameObject", "go", "Go" }; - for (int i = 0; i < gameObjectNames.Length; i++) - { - string name = gameObjectNames[i]; - - PropertyInfo prop = type.GetProperty(name, flags); - if (prop != null && typeof(GameObject).IsAssignableFrom(prop.PropertyType)) - { - GameObject go = prop.GetValue(villager, null) as GameObject; - if (go != null) - { - position = go.transform.position; - return true; - } - } - - FieldInfo field = type.GetField(name, flags); - if (field != null && typeof(GameObject).IsAssignableFrom(field.FieldType)) - { - GameObject go = field.GetValue(villager) as GameObject; - if (go != null) - { - position = go.transform.position; - return true; - } - } - } - - string[] positionNames = new string[] { "pos", "Pos", "position", "Position" }; - for (int i = 0; i < positionNames.Length; i++) - { - string name = positionNames[i]; - - PropertyInfo prop = type.GetProperty(name, flags); - if (prop != null && prop.PropertyType == typeof(Vector3)) - { - position = (Vector3)prop.GetValue(villager, null); - return true; - } - - FieldInfo field = type.GetField(name, flags); - if (field != null && field.FieldType == typeof(Vector3)) - { - position = (Vector3)field.GetValue(villager); - return true; - } - } - - string[] getPosNames = new string[] { "GetPos", "GetPosition" }; - for (int i = 0; i < getPosNames.Length; i++) - { - MethodInfo method = type.GetMethod(getPosNames[i], flags, null, new Type[0], null); - if (method != null && method.ReturnType == typeof(Vector3)) - { - position = (Vector3)method.Invoke(villager, null); - return true; - } - } - } - catch - { - } - - return false; - } - - public static void RunPostLoadRebuild(string reason) - { - try - { - helper?.Log("Post-load rebuild: " + (reason ?? string.Empty)); - - try { World.inst.SetupInitialPathCosts(); } catch (Exception e) { helper?.Log(e.ToString()); } - try { World.inst.RebuildVillagerGrid(); } catch (Exception e) { helper?.Log(e.ToString()); } - try { Player.inst.irrigation.UpdateIrrigation(); } catch (Exception e) { helper?.Log(e.ToString()); } - try { Player.inst.CalcMaxResources(null, -1); } catch (Exception e) { helper?.Log(e.ToString()); } - - try { if (UnitSystem.inst != null) UnitSystem.inst.enabled = true; } catch (Exception e) { helper?.Log(e.ToString()); } - try { if (JobSystem.inst != null) JobSystem.inst.enabled = true; } catch (Exception e) { helper?.Log(e.ToString()); } - try { if (VillagerSystem.inst != null) VillagerSystem.inst.enabled = true; } catch (Exception e) { helper?.Log(e.ToString()); } - - SetLoadTickDelay(Player.inst, 1); - SetLoadTickDelay(UnitSystem.inst, 1); - SetLoadTickDelay(JobSystem.inst, 1); - SetLoadTickDelay(VillagerSystem.inst, 1); - - try - { - // A nudge helps recover from cases where villagers have jobs but never begin moving. - SetSuppressVillagerTeleportPackets(true); - foreach (var kcPlayer in kCPlayers.Values) - { - if (kcPlayer == null || kcPlayer.inst == null) - continue; - - var workers = kcPlayer.inst.Workers; - for (int i = 0; i < workers.Count; i++) - { - Villager v = workers.data[i]; - if (v == null) - continue; - - try - { - Vector3 pos; - if (TryGetVillagerPosition(v, out pos)) - v.TeleportTo(pos); - } - catch - { - } - } - } - } - catch (Exception e) - { - helper?.Log("Post-load villager nudge failed"); - helper?.Log(e.ToString()); - } - finally - { - SetSuppressVillagerTeleportPackets(false); - } - } - catch (Exception e) - { - helper?.Log("Post-load rebuild failed"); - helper?.Log(e.ToString()); - } - } - public static Player GetPlayerByTeamID(int teamId) // Need to replace building / production types so that the correct player is used. IResourceStorage and IResourceProvider, and jobs { - KCPlayer match = kCPlayers.Values.FirstOrDefault(p => - p != null && - p.inst != null && - p.inst.PlayerLandmassOwner != null && - p.inst.PlayerLandmassOwner.teamId == teamId); - - if (match != null && match.inst != null) - return match.inst; - - if (KCServer.IsRunning || KCClient.client.IsConnected) + try { - long now = DateTimeOffset.Now.ToUnixTimeMilliseconds(); - long last; - if (!lastTeamIdLookupLogMs.TryGetValue(teamId, out last) || (now - last) > 2000) + var player = kCPlayers.Values.FirstOrDefault(p => p.inst.PlayerLandmassOwner.teamId == teamId).inst; + + return player; + } + catch (Exception e) + { + if (KCServer.IsRunning || KCClient.client.IsConnected) { - lastTeamIdLookupLogMs[teamId] = now; - - string myTeamId = (Player.inst != null && Player.inst.PlayerLandmassOwner != null) - ? Player.inst.PlayerLandmassOwner.teamId.ToString() - : "unknown"; - - Main.helper.Log("Failed finding player by teamID: " + teamId + " My teamID is: " + myTeamId); + Main.helper.Log("Failed finding player by teamID: " + teamId + " My teamID is: " + Player.inst.PlayerLandmassOwner.teamId); Main.helper.Log(kCPlayers.Count.ToString()); - Main.helper.Log(string.Join(", ", kCPlayers.Values.Where(p => p != null && p.inst != null && p.inst.PlayerLandmassOwner != null).Select(p => p.inst.PlayerLandmassOwner.teamId.ToString()))); + Main.helper.Log(string.Join(", ", kCPlayers.Values.Select(p => p.inst.PlayerLandmassOwner.teamId.ToString()))); + Main.helper.Log(e.Message); + Main.helper.Log(e.StackTrace); } } - return Player.inst; } @@ -541,147 +182,9 @@ namespace KCM #endregion public static int FixedUpdateInterval = 0; - private static int worldReadyRebuildDone = 0; - private static long lastVillagerMoveMs = 0; - private static long lastVillagerProbeMs = 0; - private static long lastVillagerStallLogMs = 0; - private static Guid probedVillagerGuid = Guid.Empty; - private static Vector3 probedVillagerLastPos = Vector3.zero; private void FixedUpdate() { - try - { - if (KCClient.client != null && - KCClient.client.IsConnected && - Volatile.Read(ref worldReadyRebuildDone) == 0 && - World.inst != null && - Player.inst != null && - VillagerSystem.inst != null) - { - if (Interlocked.Exchange(ref worldReadyRebuildDone, 1) == 0) - { - Main.helper.Log("AutoRebuild: world ready; running post-load rebuild"); - RunPostLoadRebuild("auto:world-ready"); - Main.helper.Log( - "AutoRebuild: timeScale=" + Time.timeScale + - " loadTickDelay(Player/Unit/Job/Villager)=" + - GetLoadTickDelayOrMinusOne(Player.inst) + "/" + - GetLoadTickDelayOrMinusOne(UnitSystem.inst) + "/" + - GetLoadTickDelayOrMinusOne(JobSystem.inst) + "/" + - GetLoadTickDelayOrMinusOne(VillagerSystem.inst)); - } - } - } - catch - { - } - - try - { - if (KCClient.client != null && - KCClient.client.IsConnected && - World.inst != null && - Time.timeScale > 0f && - Villager.villagers != null && - Villager.villagers.Count > 0) - { - long now = DateTimeOffset.Now.ToUnixTimeMilliseconds(); - if ((now - lastVillagerProbeMs) >= 2000) - { - lastVillagerProbeMs = now; - - // Proactively check and fix loadTickDelay every 2 seconds - int villagerDelay = GetLoadTickDelayOrMinusOne(VillagerSystem.inst); - int unitDelay = GetLoadTickDelayOrMinusOne(UnitSystem.inst); - int jobDelay = GetLoadTickDelayOrMinusOne(JobSystem.inst); - int playerDelay = GetLoadTickDelayOrMinusOne(Player.inst); - - if (villagerDelay <= 0 || unitDelay <= 0 || jobDelay <= 0 || playerDelay <= 0) - { - Main.helper.Log("LoadTickDelay refresh: delays were " + - playerDelay + "/" + unitDelay + "/" + jobDelay + "/" + villagerDelay + ", resetting to 1"); - SetLoadTickDelay(Player.inst, 1); - SetLoadTickDelay(UnitSystem.inst, 1); - SetLoadTickDelay(JobSystem.inst, 1); - SetLoadTickDelay(VillagerSystem.inst, 1); - } - - Villager v = null; - try - { - if (probedVillagerGuid != Guid.Empty) - v = Villager.villagers.data.FirstOrDefault(x => x != null && x.guid == probedVillagerGuid); - } - catch - { - } - - if (v == null) - { - v = Villager.villagers.data.FirstOrDefault(x => x != null); - if (v != null) - { - probedVillagerGuid = v.guid; - probedVillagerLastPos = v.Pos; - lastVillagerMoveMs = now; - } - } - - if (v != null) - { - float movedSqr = (v.Pos - probedVillagerLastPos).sqrMagnitude; - if (movedSqr > 0.01f) - { - probedVillagerLastPos = v.Pos; - lastVillagerMoveMs = now; - } - - // Note: We now have proactive loadTickDelay refresh above, so villager stall detection - // is less critical. Only log if there's an actual extended stall with bad delay values. - if ((now - lastVillagerMoveMs) >= 30000 && (now - lastVillagerStallLogMs) >= 30000) - { - lastVillagerStallLogMs = now; - Main.helper.Log( - "VillagerStallDetect: no movement for " + (now - lastVillagerMoveMs) + - "ms timeScale=" + Time.timeScale + - " mode=" + TryGetGameModeName() + - " villagerSystemEnabled=" + (VillagerSystem.inst != null && VillagerSystem.inst.enabled) + - " villagers=" + Villager.villagers.Count + - " sampleGuid=" + probedVillagerGuid + - " samplePos=" + v.Pos); - Main.helper.Log( - "VillagerStallDetect: loadTickDelay(Player/Unit/Job/Villager)=" + - GetLoadTickDelayOrMinusOne(Player.inst) + "/" + - GetLoadTickDelayOrMinusOne(UnitSystem.inst) + "/" + - GetLoadTickDelayOrMinusOne(JobSystem.inst) + "/" + - GetLoadTickDelayOrMinusOne(VillagerSystem.inst)); - - // Try to fix stalled systems by resetting loadTickDelay - // Reuse the delay variables from earlier in this scope - villagerDelay = GetLoadTickDelayOrMinusOne(VillagerSystem.inst); - unitDelay = GetLoadTickDelayOrMinusOne(UnitSystem.inst); - jobDelay = GetLoadTickDelayOrMinusOne(JobSystem.inst); - playerDelay = GetLoadTickDelayOrMinusOne(Player.inst); - - if (villagerDelay <= 0 || unitDelay <= 0 || jobDelay <= 0 || playerDelay <= 0) - { - Main.helper.Log("VillagerStallDetect: Attempting to fix stalled systems (delays: " + - playerDelay + "/" + unitDelay + "/" + jobDelay + "/" + villagerDelay + ")"); - SetLoadTickDelay(Player.inst, 1); - SetLoadTickDelay(UnitSystem.inst, 1); - SetLoadTickDelay(JobSystem.inst, 1); - SetLoadTickDelay(VillagerSystem.inst, 1); - } - } - } - } - } - } - catch - { - } - // send batched building placement info /*if (PlaceHook.QueuedBuildings.Count > 0 && (FixedUpdateInterval % 25 == 0)) { @@ -795,29 +298,6 @@ namespace KCM if (newState != MainMenuMode.State.Uninitialized) Main.menuState = (MenuState)newState; - - if ((MenuState)newState == MenuState.Menu && (KCClient.client.IsConnected || KCServer.IsRunning)) - ResetMultiplayerState("Returned to main menu"); - - if ((MenuState)newState == (MenuState)200 && KCClient.client.IsConnected) - { - try - { - RunPostLoadRebuild("Entered playing mode"); - } - catch - { - } - - try - { - if (SpeedControlUI.inst != null) - SpeedControlUI.inst.SetSpeed(1); - } - catch - { - } - } } } @@ -912,7 +392,10 @@ namespace KCM { public static void Postfix() { + // Your code here + // Get the name of the last method that called OnPlayerPlacement + string callTree = ""; List strings = new List(); for (int i = 1; i < 10; i++) @@ -1058,12 +541,7 @@ namespace KCM { public static bool Prefix(Player __instance) { - var localPlayer = Player.inst; - if (KCClient.client.IsConnected && - __instance != null && - (localPlayer == null || __instance != localPlayer) && - __instance.gameObject != null && - __instance.gameObject.name.Contains("Client Player")) + if (KCClient.client.IsConnected && __instance.gameObject.name.Contains("Client Player") && !LobbyManager.loadingSave) { try { @@ -1176,14 +654,26 @@ namespace KCM [HarmonyPatch(typeof(Player), "AddBuilding")] public class PlayerAddBuildingHook { + static int step = 1; + static void LogStep(bool reset = false) + { + if (reset) + step = 1; + + Main.helper.Log(step.ToString()); + step++; + } + public static bool Prefix(Player __instance, Building b) { try { if (KCClient.client.IsConnected) { + LogStep(true); __instance.Buildings.Add(b); IResourceStorage[] storages = b.GetComponents(); + LogStep(); for (int i = 0; i < storages.Length; i++) { bool flag = !storages[i].IsPrivate(); @@ -1192,38 +682,50 @@ namespace KCM FreeResourceManager.inst.AddResourceStorage(storages[i]); } } + LogStep(); int landMass = b.LandMass(); Home res = b.GetComponent(); bool flag2 = res != null; + LogStep(); if (flag2) { __instance.Residentials.Add(res); __instance.ResidentialsPerLandmass[landMass].Add(res); } WagePayer wagePayer = b.GetComponent(); + LogStep(); bool flag3 = wagePayer != null; if (flag3) { __instance.WagePayers.Add(wagePayer); } RadiusBonus radiusBonus = b.GetComponent(); + LogStep(); bool flag4 = radiusBonus != null; if (flag4) { __instance.RadiusBonuses.Add(radiusBonus); } + LogStep(); var globalBuildingRegistry = __instance.GetType().GetField("globalBuildingRegistry", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance) as ArrayExt; + LogStep(); var landMassBuildingRegistry = __instance.GetType().GetField("landMassBuildingRegistry", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance) as ArrayExt; + LogStep(); var unbuiltBuildingsPerLandmass = __instance.GetType().GetField("unbuiltBuildingsPerLandmass", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance) as ArrayExt>; + LogStep(); __instance.AddToRegistry(globalBuildingRegistry, b); + LogStep(); __instance.AddToRegistry(landMassBuildingRegistry.data[landMass].registry, b); + LogStep(); landMassBuildingRegistry.data[landMass].buildings.Add(b); + LogStep(); bool flag5 = !b.IsBuilt(); if (flag5) { unbuiltBuildingsPerLandmass.data[landMass].Add(b); } + LogStep(); return false; @@ -1479,77 +981,39 @@ namespace KCM public class SpeedControlUISetSpeedHook { private static long lastTime = 0; - private static long lastClientBlockLogTime = 0; - private static long lastHostPauseTraceLogTime = 0; - private static int lastSentSpeed = -1; - public static bool Prefix(int idx, ref bool __state) + public static bool Prefix() { - __state = false; - if (!KCClient.client.IsConnected) - return true; - - bool calledFromPacket = false; - try { calledFromPacket = PacketHandler.IsHandlingPacket; } catch { } - - // In multiplayer, keep time control authoritative to the host to avoid clients pausing/stalling the simulation. - if (!KCServer.IsRunning) + if (KCClient.client.IsConnected) { - if (calledFromPacket) - return true; + if ((DateTimeOffset.Now.ToUnixTimeMilliseconds() - lastTime) < 250) // Set speed spam fix / hack + return false; - long now = DateTimeOffset.Now.ToUnixTimeMilliseconds(); - if ((now - lastClientBlockLogTime) >= 2000) - { - lastClientBlockLogTime = now; - Main.helper.Log("Blocked SpeedControlUI.SetSpeed on non-host client: " + idx); - } - - return false; - } - - if (!calledFromPacket) - { - long now = DateTimeOffset.Now.ToUnixTimeMilliseconds(); - // Ensure that real speed changes are always propagated, even if they happen in quick succession (eg. pause/unpause). - if (idx != lastSentSpeed || (now - lastTime) >= 250) // Set speed spam fix / hack - __state = true; - - // Diagnostics for "random pause": log a stack trace when the host hits speed 0 from local code. - if (idx == 0 && (now - lastHostPauseTraceLogTime) >= 2000) - { - lastHostPauseTraceLogTime = now; - try - { - Main.helper.Log("Host speed set to 0 (pause). Call stack:"); - Main.helper.Log(new StackTrace(2, false).ToString()); - } - catch - { - } - } + if (!new StackFrame(3).GetMethod().Name.Contains("HandlePacket")) + return false; } return true; } - public static void Postfix(int idx, bool skipNextSfx, bool __state) + public static void Postfix(int idx, bool skipNextSfx) { if (KCClient.client.IsConnected) { - if (!__state) + /*Main.helper.Log($"set speed Called by 0: {new StackFrame(0).GetMethod()} {new StackFrame(0).GetMethod().Name.Contains("HandlePacket")}"); + Main.helper.Log($"set speed Called by 1: {new StackFrame(1).GetMethod()} {new StackFrame(1).GetMethod().Name.Contains("HandlePacket")}"); + Main.helper.Log($"set speed Called by 2: {new StackFrame(2).GetMethod()} {new StackFrame(2).GetMethod().Name.Contains("HandlePacket")}"); + Main.helper.Log($"set speed Called by 3: {new StackFrame(3).GetMethod()} {new StackFrame(3).GetMethod().Name.Contains("HandlePacket")}");*/ + + if (new StackFrame(3).GetMethod().Name.Contains("HandlePacket")) return; - Main.helper.Log("SpeedControlUI.SetSpeed (local): " + idx); - bool isPaused = (idx == 0); new SetSpeed() { - speed = idx, - isPaused = isPaused + speed = idx }.Send(); lastTime = DateTimeOffset.Now.ToUnixTimeMilliseconds(); - lastSentSpeed = idx; } } } @@ -1658,12 +1122,7 @@ namespace KCM { if (KCClient.client.IsConnected) { - if (ShouldSuppressVillagerTeleportPackets) - return; - - bool calledFromPacket = false; - try { calledFromPacket = PacketHandler.IsHandlingPacket; } catch { } - if (calledFromPacket) + if (new StackFrame(3).GetMethod().Name.Contains("HandlePacket")) return; new VillagerTeleportTo() @@ -1711,13 +1170,18 @@ namespace KCM public static bool Prefix(ref string __result) { Main.helper.Log("Get save dir"); - if (KCServer.IsRunning) + if (KCClient.client.IsConnected) { + if (KCServer.IsRunning) + { + + } __result = Application.persistentDataPath + "/Saves/Multiplayer"; + return false; } - __result = Application.persistentDataPath + "/Saves"; + __result = Application.persistentDataPath + "/Saves"; ; return true; } } @@ -1728,13 +1192,11 @@ namespace KCM //public static string saveFile = ""; public static byte[] saveData = new byte[0]; - public static bool Prefix(string path, string filename, bool visitedWorld, ref bool __state) + public static bool Prefix(string path, string filename, bool visitedWorld) { - __state = false; if (KCServer.IsRunning) { Main.helper.Log("Trying to load multiplayer save"); - KCM.StateManagement.Observers.StateObserver.ClearAll(); LoadSave.LastLoadDirectory = path; path = path + "/" + filename; @@ -1744,18 +1206,13 @@ namespace KCM { BinaryFormatter bf = new BinaryFormatter(); bf.Binder = new MultiplayerSaveDeserializationBinder(); - Stream file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - MultiplayerSaveContainer loadData = null; + saveData = File.ReadAllBytes(path); + Stream file = new FileStream(path, FileMode.Open); try { - object deserialized = bf.Deserialize(file); - loadData = deserialized as MultiplayerSaveContainer; - if (loadData == null) - { - Main.helper.Log("Selected save is not a MultiplayerSaveContainer; falling back to vanilla load."); - saveData = new byte[0]; - return true; - } + MultiplayerSaveContainer loadData = (MultiplayerSaveContainer)bf.Deserialize(file); + loadData.Unpack(null); + Broadcast.OnLoadedEvent.Broadcast(new OnLoadedEvent()); } catch (Exception e) { @@ -1774,38 +1231,6 @@ namespace KCM file.Dispose(); } } - - try - { - saveData = File.ReadAllBytes(path); - } - catch (Exception e) - { - saveData = new byte[0]; - Main.helper.Log("Failed reading save bytes for transfer; clients will not be able to load this save."); - Main.helper.Log(e.ToString()); - } - - try - { - Main.SetMultiplayerSaveLoadInProgress(true); - __state = true; - loadData.Unpack(null); - } - finally - { - Main.SetMultiplayerSaveLoadInProgress(false); - } - - try - { - RunPostLoadRebuild("LoadAtPath (multiplayer)"); - } - catch - { - } - - Broadcast.OnLoadedEvent.Broadcast(new OnLoadedEvent()); } return false; @@ -1813,17 +1238,6 @@ namespace KCM return true; } - - public static void Postfix(string path, string filename, bool visitedWorld, bool __state) - { - if (!KCClient.client.IsConnected) - return; - - if (__state) - return; - - RunPostLoadRebuild("LoadAtPath (vanilla)"); - } } [HarmonyPatch(typeof(LoadSave), "Load")] @@ -1906,33 +1320,19 @@ namespace KCM { Directory.CreateDirectory(LoadSave.GetSaveDir()); Guid guid = Guid.NewGuid(); - bool hasOverride = !string.IsNullOrWhiteSpace(pathOverride); - string path = hasOverride ? pathOverride : Path.Combine(LoadSave.GetSaveDir(), guid.ToString()); - if (hasOverride && !Path.IsPathRooted(path)) - path = Path.Combine(LoadSave.GetSaveDir(), pathOverride); + string path = (pathOverride != "") ? pathOverride : (LoadSave.GetSaveDir() + "/" + guid); Directory.CreateDirectory(path); Thread thread; try { thread = new Thread(new ParameterizedThreadStart(OutToFile)); - MultiplayerSaveContainer packedData; - try - { - packedData = new MultiplayerSaveContainer().Pack(null); - } - catch (Exception ex) - { - Main.helper.Log("Failed to pack multiplayer save data; falling back to vanilla save."); - Main.helper.Log(ex.ToString()); - __result = null; - return true; - } + MultiplayerSaveContainer packedData = new MultiplayerSaveContainer().Pack(null); Broadcast.OnSaveEvent.Broadcast(new OnSaveEvent()); thread.Start(new OutData { LoadSaveContainer = packedData, - Path = Path.Combine(path, "world") + Path = path + "/world" }); } catch (Exception e) @@ -1964,7 +1364,7 @@ namespace KCM try { - World.inst.TakeScreenshot(Path.Combine(path, "cover"), new Func(World.inst.Func_CaptureWorldShot), onCompleteCallback); + World.inst.TakeScreenshot(path + "/cover", new Func(World.inst.Func_CaptureWorldShot), onCompleteCallback); } catch (Exception e3) { @@ -2015,7 +1415,7 @@ namespace KCM { public static bool Prefix(Building.BuildingSaveData structureData, Player p, ref Building __result) { - if (KCClient.client.IsConnected && Main.IsMultiplayerSaveLoadInProgress) + if (KCClient.client.IsConnected) { Building Building = GameState.inst.GetPlaceableByUniqueName(structureData.uniqueName); @@ -2033,23 +1433,11 @@ namespace KCM Main.helper.Log($"loading building: {building.FriendlyName}"); Main.helper.Log($" (teamid: {building.TeamID()})"); Main.helper.Log(p.ToString()); - - try + bool flag2 = building.GetComponent() != null && building.TeamID() == p.PlayerLandmassOwner.teamId; + Main.helper.Log("Set keep? " + flag2); + if (flag2) { - p.PlayerLandmassOwner.TakeOwnership(building.LandMass()); - } - catch (Exception e) - { - Main.helper.Log("Failed setting landmass ownership during load"); - Main.helper.Log(e.Message); - } - - var keep = building.GetComponent(); - bool shouldSetKeep = keep != null && p.keep == null; - Main.helper.Log("Set keep? " + shouldSetKeep); - if (shouldSetKeep) - { - p.keep = keep; + p.keep = building.GetComponent(); Main.helper.Log(p.keep.ToString()); } __result = building; @@ -2075,12 +1463,6 @@ namespace KCM if (KCClient.client.IsConnected) { var bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic; - var landmassOwner = p.PlayerLandmassOwner; - if (landmassOwner == null) - { - Main.helper.Log("PlayerLandmassOwner was null during PlayerSaveData.Pack; using vanilla save pack."); - return true; - } Main.helper.Log("Running patched player pack method"); Main.helper.Log("Saving banner system"); @@ -2088,12 +1470,22 @@ namespace KCM Main.helper.Log("Saving player creativeMode"); __instance.creativeMode = p.creativeMode; + //cmo options not used for saving or loading in multiplayer + /**for (int i = 0; i < p.cmoOptionsOn.Length; i++) + { + bool flag = p.cmoOptionsOn[i]; + if (flag) + { + __instance.cmoOptions.Add((Player.CreativeOptions)i); + } + }**/ + Main.helper.Log("Saving player upgrades"); __instance.GetType().GetField("upgrades", bindingFlags).SetValue(__instance, new List()); - Main.helper.Log("Saving player bannerIdx"); - __instance.bannerIdx = landmassOwner.bannerIdx; + Main.helper.Log("Saving player bannerIdx"); + __instance.bannerIdx = p.PlayerLandmassOwner.bannerIdx; Main.helper.Log("Saving player WorkersArray"); __instance.WorkersArray = new Villager.VillagerSaveData[p.Workers.Count]; @@ -2106,13 +1498,11 @@ namespace KCM } } - Main.helper.Log("Saving player HomelessData"); + Main.helper.Log("Saving player HomelessData"); __instance.HomelessData = new List(); for (int k = 0; k < p.Homeless.Count; k++) { - var homeless = p.Homeless.data[k]; - if (homeless != null) - __instance.HomelessData.Add(homeless.guid); + __instance.HomelessData.Add(p.Homeless.data[k].guid); } __instance.structures = new List(); __instance.subStructures = new List(); @@ -2120,35 +1510,17 @@ namespace KCM Main.helper.Log("Saving player structures"); World.inst.ForEachTile(0, 0, World.inst.GridWidth, World.inst.GridHeight, delegate (int x, int z, Cell cell) { - if (cell == null) - return; - - bool flag4 = cell.OccupyingStructure != null && cell.OccupyingStructure.Count > 0; + bool flag4 = cell.OccupyingStructure.Count > 0; if (flag4) { List occupyingStructureData = new List(); for (int i3 = 0; i3 < cell.OccupyingStructure.Count; i3++) { var building = cell.OccupyingStructure[i3]; - if (building == null) - continue; - - var buildingTransform = building.transform; - if (buildingTransform == null) - continue; - - bool flag5 = Vector3.Distance(buildingTransform.position.xz(), cell.Position.xz()) <= 1E-05f; - if (flag5 && building.TeamID() == landmassOwner.teamId) + bool flag5 = Vector3.Distance(cell.OccupyingStructure[i3].transform.position.xz(), cell.Position.xz()) <= 1E-05f; + if (flag5 && building.TeamID() == p.PlayerLandmassOwner.teamId) { - try - { - occupyingStructureData.Add(new Building.BuildingSaveData().Pack(building)); - } - catch (Exception ex) - { - Main.helper.Log("Error packing structure for save: " + (building.UniqueName ?? string.Empty)); - Main.helper.Log(ex.ToString()); - } + occupyingStructureData.Add(new Building.BuildingSaveData().Pack(cell.OccupyingStructure[i3])); } } bool flag6 = occupyingStructureData.Count > 0; @@ -2157,32 +1529,17 @@ namespace KCM __instance.structures.Add(occupyingStructureData.ToArray()); } } - bool flag7 = cell.SubStructure != null && cell.SubStructure.Count > 0; + bool flag7 = cell.SubStructure.Count > 0; if (flag7) { List subStructureData = new List(); for (int i4 = 0; i4 < cell.SubStructure.Count; i4++) { var building = cell.SubStructure[i4]; - if (building == null) - continue; - - var buildingTransform = building.transform; - if (buildingTransform == null) - continue; - - bool flag8 = Vector3.Distance(buildingTransform.position.xz(), cell.Position.xz()) <= 1E-05f; - if (flag8 && building.TeamID() == landmassOwner.teamId) + bool flag8 = Vector3.Distance(cell.SubStructure[i4].transform.position.xz(), cell.Position.xz()) <= 1E-05f; + if (flag8 && building.TeamID() == p.PlayerLandmassOwner.teamId) { - try - { - subStructureData.Add(new Building.BuildingSaveData().Pack(building)); - } - catch (Exception ex) - { - Main.helper.Log("Error packing sub-structure for save: " + (building.UniqueName ?? string.Empty)); - Main.helper.Log(ex.ToString()); - } + subStructureData.Add(new Building.BuildingSaveData().Pack(cell.SubStructure[i4])); } } bool flag9 = subStructureData.Count > 0; @@ -2776,19 +2133,7 @@ namespace KCM { Assembly assembly = typeof(Building).Assembly; - Type[] allTypes; - try - { - allTypes = assembly.GetTypes(); - } - catch (ReflectionTypeLoadException e) - { - allTypes = e.Types.Where(t => t != null).ToArray(); - } - - var types = allTypes - .Where(t => t != null && typeof(Building).IsAssignableFrom(t) && !t.IsAbstract) - .ToArray(); + 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)) @@ -2833,56 +2178,6 @@ namespace KCM } } - [HarmonyPatch] - public class FieldSystemPlayerReferencePatch - { - static FieldInfo playerField; - - static IEnumerable TargetMethods() - { - var methodsInNamespace = typeof(FieldSystem) - .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(); - } - - static IEnumerable Transpiler(MethodBase method, IEnumerable instructions) - { - if (playerField == null) - { - var bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; - playerField = typeof(FieldSystem).GetFields(bindingFlags).FirstOrDefault(f => f.FieldType == typeof(Player)); - } - - if (playerField == null) - return instructions; - - int playerInstCount = 0; - - var codes = new List(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; - codes[i].operand = null; - codes.Insert(++i, new CodeInstruction(OpCodes.Ldfld, playerField)); - } - } - - if (playerInstCount > 0) - Main.helper.Log($"Found {playerInstCount} static FieldSystem Player.inst references in {method.Name}"); - - return codes.AsEnumerable(); - } - } - [HarmonyPatch] public class PlayerPatch diff --git a/Packets/Game/GameVillager/VillagerSnapshotPacket.cs b/Packets/Game/GameVillager/VillagerSnapshotPacket.cs deleted file mode 100644 index 696890b..0000000 --- a/Packets/Game/GameVillager/VillagerSnapshotPacket.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace KCM.Packets.Game.GameVillager -{ - public class VillagerSnapshotPacket : Packet - { - public override ushort packetId => (ushort)Enums.Packets.VillagerSnapshot; - - public List guids { get; set; } = new List(); - public List positions { get; set; } = new List(); - - public override void HandlePacketClient() - { - if (KCClient.client != null && clientId == KCClient.client.Id) - return; - - try - { - int count = Math.Min(guids?.Count ?? 0, positions?.Count ?? 0); - if (count == 0) - return; - - for (int i = 0; i < count; i++) - { - Guid guid = guids[i]; - Vector3 position = positions[i]; - - Villager villager = null; - try - { - villager = Villager.villagers?.data.FirstOrDefault(v => v != null && v.guid == guid); - } - catch - { - } - - if (villager == null) - continue; - - villager.TeleportTo(position); - } - } - catch (Exception e) - { - Main.helper.Log("Error handling villager snapshot packet: " + e.Message); - } - } - - public override void HandlePacketServer() - { - } - } -} diff --git a/Packets/Game/SetSpeed.cs b/Packets/Game/SetSpeed.cs index 3fa81b4..319eb71 100644 --- a/Packets/Game/SetSpeed.cs +++ b/Packets/Game/SetSpeed.cs @@ -1,9 +1,8 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using UnityEngine; namespace KCM.Packets.Game { @@ -12,30 +11,18 @@ namespace KCM.Packets.Game public override ushort packetId => (int)Enums.Packets.SetSpeed; public int speed { get; set; } - public bool isPaused { get; set; } public override void HandlePacketClient() { if (clientId == KCClient.client.Id) // Prevent speed softlock return; - try - { - Main.helper.Log($"Received SetSpeed packet: speed={speed}, isPaused={isPaused}"); - - // Simply apply the speed - SpeedControlUISetSpeedHook will handle this correctly - // since we're coming from a packet (PacketHandler.IsHandlingPacket will be true) - SpeedControlUI.inst.SetSpeed(speed); - } - catch (Exception e) - { - Main.helper.Log("Error handling SetSpeed packet: " + e.Message); - } + SpeedControlUI.inst.SetSpeed(speed); } public override void HandlePacketServer() { - // Server relay is handled automatically by PacketHandler unless [NoServerRelay] is used. + //throw new NotImplementedException(); } } } diff --git a/Packets/Handlers/LobbyHandler.cs b/Packets/Handlers/LobbyHandler.cs index 686f0f3..34f8a74 100644 --- a/Packets/Handlers/LobbyHandler.cs +++ b/Packets/Handlers/LobbyHandler.cs @@ -35,7 +35,6 @@ namespace KCM.Packets.Handlers if (!KCServer.IsRunning) { Main.kCPlayers.Clear(); - Main.clientSteamIds.Clear(); } } catch (Exception ex) diff --git a/Packets/Handlers/PacketHandler.cs b/Packets/Handlers/PacketHandler.cs index ce7c7cf..bbafed6 100644 --- a/Packets/Handlers/PacketHandler.cs +++ b/Packets/Handlers/PacketHandler.cs @@ -15,14 +15,6 @@ namespace KCM.Packets.Handlers { public class PacketHandler { - [ThreadStatic] - private static bool isHandlingPacket; - - public static bool IsHandlingPacket - { - get { return isHandlingPacket; } - } - public static Dictionary Packets = new Dictionary(); public class PacketRef { @@ -92,9 +84,7 @@ namespace KCM.Packets.Handlers { IPacket p = (IPacket)Activator.CreateInstance(packet); - var properties = packet.GetProperties(BindingFlags.Instance | BindingFlags.Public) - .Where(prop => prop.Name != "packetId" && prop.Name != "sendMode") - .ToArray(); + var properties = packet.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(prop => prop.Name != "packetId").ToArray(); Array.Sort(properties, (x, y) => String.Compare(x.Name, y.Name)); ushort id = (ushort)p.GetType().GetProperty("packetId").GetValue(p, null); @@ -147,9 +137,7 @@ namespace KCM.Packets.Handlers { packet.HandlePacketServer(); - bool shouldRelay = packet.GetType().GetCustomAttributes(typeof(NoServerRelayAttribute), inherit: true).Length == 0; - if (shouldRelay) - ((Packet)packet).SendToAll(); + ((Packet)packet).SendToAll(); } catch (Exception ex) { @@ -191,7 +179,6 @@ namespace KCM.Packets.Handlers { try { - isHandlingPacket = true; packet.HandlePacketClient(); } catch (Exception ex) @@ -214,10 +201,6 @@ namespace KCM.Packets.Handlers Main.helper.Log(ex.InnerException.StackTrace); } } - finally - { - isHandlingPacket = false; - } } /* if (PacketHandlers.TryGetValue(id, out PacketHandlerDelegate handler)) @@ -239,20 +222,14 @@ namespace KCM.Packets.Handlers try { var packetRef = Packets[packet.packetId]; - - MessageSendMode sendMode = MessageSendMode.Reliable; - Packet basePacket = packet as Packet; - if (basePacket != null) - sendMode = basePacket.sendMode; - - Message message = Message.Create(sendMode, packet.packetId); + Message message = Message.Create(MessageSendMode.Reliable, packet.packetId); foreach (var prop in packetRef.properties) { if (prop.PropertyType.IsEnum) { currentPropName = prop.Name; - message.AddInt(Convert.ToInt32(prop.GetValue(packet, null))); + message.AddInt((int)prop.GetValue(packet, null)); } else if (prop.PropertyType == typeof(ushort)) { @@ -323,27 +300,6 @@ namespace KCM.Packets.Handlers message.AddInt(item); } - else if (prop.PropertyType == typeof(List)) - { - currentPropName = prop.Name; - List list = (List)prop.GetValue(packet, null); - message.AddInt(list.Count); - foreach (var item in list) - message.AddBytes(item.ToByteArray(), true); - } - else if (prop.PropertyType == typeof(List)) - { - currentPropName = prop.Name; - List list = (List)prop.GetValue(packet, null); - message.AddInt(list.Count); - foreach (var item in list) - { - message.AddFloat(item.x); - message.AddFloat(item.y); - message.AddFloat(item.z); - } - } - else if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) { currentPropName = prop.Name; @@ -505,7 +461,9 @@ namespace KCM.Packets.Handlers if (prop.PropertyType.IsEnum) { int enumValue = message.GetInt(); - prop.SetValue(p, Enum.ToObject(prop.PropertyType, enumValue)); + string enumName = Enum.GetName(prop.PropertyType, enumValue); + + prop.SetValue(p, Enum.Parse(prop.PropertyType, enumName)); } else if (prop.PropertyType == typeof(ushort)) { @@ -577,29 +535,6 @@ namespace KCM.Packets.Handlers prop.SetValue(p, list); } - else if (prop.PropertyType == typeof(List)) - { - int count = message.GetInt(); - List list = new List(); - - for (int i = 0; i < count; i++) - list.Add(new Guid(message.GetBytes())); - - prop.SetValue(p, list); - } - else if (prop.PropertyType == typeof(List)) - { - int count = message.GetInt(); - List list = new List(); - - for (int i = 0; i < count; i++) - { - Vector3 vector = new Vector3(message.GetFloat(), message.GetFloat(), message.GetFloat()); - list.Add(vector); - } - - prop.SetValue(p, list); - } else if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) { IDictionary dictionary = (IDictionary)prop.GetValue(p, null); diff --git a/Packets/Lobby/PlayerList.cs b/Packets/Lobby/PlayerList.cs index 9bf341e..3597da8 100644 --- a/Packets/Lobby/PlayerList.cs +++ b/Packets/Lobby/PlayerList.cs @@ -35,17 +35,13 @@ namespace KCM.Packets.Lobby Main.helper.Log("PlayerList: " + playersName[i] + " " + playersId[i] + " " + steamIds[i]); - KCPlayer player; - if (!Main.kCPlayers.TryGetValue(steamIds[i], out player) || player == null) + Main.kCPlayers.Add(steamIds[i], new KCPlayer(playersName[i], playersId[i], steamIds[i]) { - player = new KCPlayer(playersName[i], playersId[i], steamIds[i]); - Main.kCPlayers[steamIds[i]] = player; - } - - player.name = playersName[i]; - player.ready = playersReady[i]; - player.banner = playersBanner[i]; - player.kingdomName = playersKingdomName[i]; + name = playersName[i], + ready = playersReady[i], + banner = playersBanner[i], + kingdomName = playersKingdomName[i] + }); if (Main.clientSteamIds.ContainsKey(playersId[i])) @@ -53,8 +49,7 @@ namespace KCM.Packets.Lobby else Main.clientSteamIds.Add(playersId[i], steamIds[i]); - if (player.inst != null && player.inst.PlayerLandmassOwner != null) - player.inst.PlayerLandmassOwner.SetBannerIdx(playersBanner[i]); + Main.kCPlayers[steamIds[i]].inst.PlayerLandmassOwner.SetBannerIdx(playersBanner[i]); LobbyHandler.AddPlayerEntry(playersId[i]); } diff --git a/Packets/Lobby/PlayerReady.cs b/Packets/Lobby/PlayerReady.cs index 680154c..e8957f5 100644 --- a/Packets/Lobby/PlayerReady.cs +++ b/Packets/Lobby/PlayerReady.cs @@ -14,8 +14,6 @@ namespace KCM.Packets.Lobby public override void HandlePacketServer() { - if (player == null) - return; IsReady = !player.ready; //SendToAll(KCClient.client.Id); @@ -24,8 +22,6 @@ namespace KCM.Packets.Lobby public override void HandlePacketClient() { - if (player == null) - return; player.ready = IsReady; } } diff --git a/Packets/Lobby/SaveTransferPacket.cs b/Packets/Lobby/SaveTransferPacket.cs index 0bd1eb9..18282e6 100644 --- a/Packets/Lobby/SaveTransferPacket.cs +++ b/Packets/Lobby/SaveTransferPacket.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; -using KCM.StateManagement.Observers; using static KCM.Main; namespace KCM.Packets.Lobby @@ -18,14 +17,6 @@ namespace KCM.Packets.Lobby public static bool loadingSave = false; public static int received = 0; - public static void ResetTransferState() - { - loadingSave = false; - received = 0; - saveData = new byte[1]; - chunksReceived = new bool[1]; - } - public int chunkId { get; set; } public int chunkSize { get; set; } @@ -38,56 +29,38 @@ namespace KCM.Packets.Lobby public override void HandlePacketClient() { - bool initialisingTransfer = !loadingSave || - saveData == null || - saveData.Length != saveSize || - chunksReceived == null || - chunksReceived.Length != totalChunks; + float savePercent = (float)received / (float)saveSize; - if (initialisingTransfer) + // Initialize saveData and chunksReceived on the first packet received + if (saveData.Length == 1) { + Main.helper.Log("Save Transfer started!"); loadingSave = true; - received = 0; - StateObserver.ClearAll(); + ServerLobbyScript.LoadingSave.SetActive(true); + + // save percentage + saveData = new byte[saveSize]; chunksReceived = new bool[totalChunks]; - - if (ServerLobbyScript.LoadingSave != null) - ServerLobbyScript.LoadingSave.SetActive(true); } - if (chunkId < 0 || chunkId >= totalChunks) - { - Main.helper.Log($"Invalid save chunk id: {chunkId} / {totalChunks}"); - return; - } - - if (saveDataChunk == null) - { - Main.helper.Log($"Null save chunk data for chunk: {chunkId}"); - return; - } - - if (saveDataIndex < 0 || saveDataIndex + saveDataChunk.Length > saveData.Length) - { - Main.helper.Log($"Invalid save chunk write range: index={saveDataIndex} len={saveDataChunk.Length} size={saveData.Length}"); - return; - } + // Copy the chunk data into the correct position in saveData Array.Copy(saveDataChunk, 0, saveData, saveDataIndex, saveDataChunk.Length); + + // Mark this chunk as received chunksReceived[chunkId] = true; + + // Seek to the next position to write to received += chunkSize; - float savePercent = saveSize > 0 ? (float)received / (float)saveSize : 0f; - if (ServerLobbyScript.ProgressBar != null) - ServerLobbyScript.ProgressBar.fillAmount = savePercent; - if (ServerLobbyScript.ProgressBarText != null) - ServerLobbyScript.ProgressBarText.text = (savePercent * 100).ToString("0.00") + "%"; - if (ServerLobbyScript.ProgressText != null) - ServerLobbyScript.ProgressText.text = $"{((float)(received / 1000)).ToString("0.00")} KB / {((float)(saveSize / 1000)).ToString("0.00")} KB"; + + ServerLobbyScript.ProgressBar.fillAmount = savePercent; + ServerLobbyScript.ProgressBarText.text = (savePercent * 100).ToString("0.00") + "%"; + ServerLobbyScript.ProgressText.text = $"{((float)(received / 1000)).ToString("0.00")} KB / {((float)(saveSize / 1000)).ToString("0.00")} KB"; if (chunkId + 1 == totalChunks) @@ -108,40 +81,11 @@ namespace KCM.Packets.Lobby LoadSave.Load(); - try - { - Main.SetMultiplayerSaveLoadInProgress(true); - LoadSaveLoadHook.saveContainer.Unpack(null); - } - finally - { - Main.SetMultiplayerSaveLoadInProgress(false); - } - try - { - RunPostLoadRebuild("Save transfer complete"); - } - catch - { - } + LoadSaveLoadHook.saveContainer.Unpack(null); Broadcast.OnLoadedEvent.Broadcast(new OnLoadedEvent()); - try - { - new KCM.Packets.Network.ResyncRequestPacket { reason = "post-load" }.Send(); - } - catch - { - } - - if (ServerLobbyScript.LoadingSave != null) - ServerLobbyScript.LoadingSave.SetActive(false); - - loadingSave = false; - received = 0; - saveData = new byte[1]; - chunksReceived = new bool[1]; + ServerLobbyScript.LoadingSave.SetActive(false); } } diff --git a/Packets/Lobby/StartGame.cs b/Packets/Lobby/StartGame.cs index ab2ab39..eefcfcf 100644 --- a/Packets/Lobby/StartGame.cs +++ b/Packets/Lobby/StartGame.cs @@ -25,7 +25,6 @@ namespace KCM.Packets.Lobby try { - int desiredSpeed = 1; if (!LobbyManager.loadingSave) { SpeedControlUI.inst.SetSpeed(0); @@ -40,13 +39,12 @@ namespace KCM.Packets.Lobby Main.helper.Log(ex.ToString()); } - SpeedControlUI.inst.SetSpeed(desiredSpeed); + SpeedControlUI.inst.SetSpeed(0); } else { LobbyManager.loadingSave = false; GameState.inst.SetNewMode(GameState.inst.playingMode); - SpeedControlUI.inst.SetSpeed(desiredSpeed); } } catch (Exception ex) diff --git a/Packets/Lobby/WorldSeed.cs b/Packets/Lobby/WorldSeed.cs index f3970f4..38655c9 100644 --- a/Packets/Lobby/WorldSeed.cs +++ b/Packets/Lobby/WorldSeed.cs @@ -33,14 +33,6 @@ namespace KCM.Packets.Lobby World.inst.Generate(Seed); Vector3 center = World.inst.GetCellData(World.inst.GridWidth / 2, World.inst.GridHeight / 2).Center; Cam.inst.SetTrackingPos(center); - - try - { - new KCM.Packets.Network.ResyncRequestPacket { reason = "post-world-seed" }.Send(); - } - catch - { - } } catch (Exception e) { diff --git a/Packets/Network/ClientConnected.cs b/Packets/Network/ClientConnected.cs index 9c8abac..6c55639 100644 --- a/Packets/Network/ClientConnected.cs +++ b/Packets/Network/ClientConnected.cs @@ -51,20 +51,6 @@ namespace KCM.Packets.Network { Main.helper.Log("Server Player Connected: " + Name + " Id: " + clientId + " SteamID: " + SteamId); - KCPlayer player; - if (Main.kCPlayers.TryGetValue(SteamId, out player)) - { - player.id = clientId; - player.name = Name; - player.steamId = SteamId; - } - else - { - Main.kCPlayers[SteamId] = new KCPlayer(Name, clientId, SteamId); - } - - Main.clientSteamIds[clientId] = SteamId; - List list = Main.kCPlayers.Select(x => x.Value).OrderBy(x => x.id).ToList(); if (list.Count > 0) @@ -92,7 +78,36 @@ namespace KCM.Packets.Network return; byte[] bytes = LoadSaveLoadAtPathHook.saveData; - KCServer.EnqueueSaveTransfer(clientId, bytes); + int chunkSize = 900; // 900 bytes per chunk to fit within packet size limit + + List chunks = SplitByteArrayIntoChunks(bytes, chunkSize); + Main.helper.Log("Save Transfer started!"); + + int sent = 0; + int packetsSent = 0; + + for (int i = 0; i < chunks.Count; i++) + { + var chunk = chunks[i]; + + + new SaveTransferPacket() + { + saveSize = bytes.Length, + saveDataChunk = chunk, + chunkId = i, + chunkSize = chunk.Length, + saveDataIndex = sent, + totalChunks = chunks.Count + }.Send(clientId); + + Main.helper.Log(" "); + + packetsSent++; + sent += chunk.Length; + } + + Main.helper.Log($"Sent {packetsSent} save data chunks to client"); } else { diff --git a/Packets/Network/ResyncRequestPacket.cs b/Packets/Network/ResyncRequestPacket.cs deleted file mode 100644 index f810989..0000000 --- a/Packets/Network/ResyncRequestPacket.cs +++ /dev/null @@ -1,35 +0,0 @@ -using KCM.Attributes; -using KCM.StateManagement.Sync; -using System; - -namespace KCM.Packets.Network -{ - [NoServerRelay] - public class ResyncRequestPacket : Packet - { - public override ushort packetId => (ushort)Enums.Packets.ResyncRequest; - - public string reason { get; set; } - - public override void HandlePacketClient() - { - } - - public override void HandlePacketServer() - { - try - { - if (!KCServer.IsRunning) - return; - - SyncManager.SendResyncToClient(clientId, reason); - } - catch (Exception ex) - { - Main.helper.Log("Error handling ResyncRequestPacket on server"); - Main.helper.Log(ex.ToString()); - } - } - } -} - diff --git a/Packets/Network/ServerHandshake.cs b/Packets/Network/ServerHandshake.cs index 099d795..a605357 100644 --- a/Packets/Network/ServerHandshake.cs +++ b/Packets/Network/ServerHandshake.cs @@ -38,8 +38,7 @@ namespace KCM.Packets.Network Main.helper.Log("Sending client connected. Client ID is: " + clientId); - Main.kCPlayers[Main.PlayerSteamID] = new KCPlayer(KCClient.inst.Name, clientId, Main.PlayerSteamID); - Main.clientSteamIds[clientId] = Main.PlayerSteamID; + Main.kCPlayers.Add(Main.PlayerSteamID, new KCPlayer(KCClient.inst.Name, clientId, Main.PlayerSteamID)); Player.inst.PlayerLandmassOwner.teamId = clientId * 10 + 2; diff --git a/Packets/Packet.cs b/Packets/Packet.cs index 69c61cb..0764cff 100644 --- a/Packets/Packet.cs +++ b/Packets/Packet.cs @@ -11,21 +11,25 @@ namespace KCM.Packets { public abstract ushort packetId { get; } public ushort clientId { get; set; } - public virtual Riptide.MessageSendMode sendMode => Riptide.MessageSendMode.Reliable; public KCPlayer player { get { - string steamId; - if (!Main.clientSteamIds.TryGetValue(clientId, out steamId) || string.IsNullOrEmpty(steamId)) + KCPlayer p = null; + + if (!Main.clientSteamIds.ContainsKey(clientId)) return null; - KCPlayer player; - if (Main.kCPlayers.TryGetValue(steamId, out player)) - return player; + //Main.helper.Log($"SteamID: {Main.GetPlayerByClientID(clientId).steamId} for {clientId} ({Main.GetPlayerByClientID(clientId).id})"); + + if (Main.kCPlayers.TryGetValue(Main.GetPlayerByClientID(clientId).steamId, out p)) + return p; + else + { + Main.helper.Log($"Error getting player from packet {packetId} {this.GetType().Name} from {clientId}"); + } - Main.helper.Log($"Error getting player from packet {packetId} {GetType().Name} from {clientId}"); return null; } } diff --git a/Packets/State/BuildingSnapshotPacket.cs b/Packets/State/BuildingSnapshotPacket.cs deleted file mode 100644 index 2f5375e..0000000 --- a/Packets/State/BuildingSnapshotPacket.cs +++ /dev/null @@ -1,33 +0,0 @@ -using KCM.StateManagement.Sync; -using System; - -namespace KCM.Packets.State -{ - public class BuildingSnapshotPacket : Packet - { - public override ushort packetId => (ushort)Enums.Packets.BuildingSnapshot; - - public byte[] payload { get; set; } - - public override void HandlePacketClient() - { - try - { - if (payload == null || payload.Length == 0) - return; - - SyncManager.ApplyBuildingSnapshot(payload); - } - catch (Exception ex) - { - Main.helper.Log("Error applying BuildingSnapshotPacket"); - Main.helper.Log(ex.ToString()); - } - } - - public override void HandlePacketServer() - { - } - } -} - diff --git a/Packets/State/BuildingStatePacket.cs b/Packets/State/BuildingStatePacket.cs index e120ba5..70ea74b 100644 --- a/Packets/State/BuildingStatePacket.cs +++ b/Packets/State/BuildingStatePacket.cs @@ -11,7 +11,6 @@ namespace KCM.Packets.State public class BuildingStatePacket : Packet { public override ushort packetId => (ushort)Enums.Packets.BuildingStatePacket; - public override Riptide.MessageSendMode sendMode => Riptide.MessageSendMode.Unreliable; public string customName { get; set; } public Guid guid { get; set; } diff --git a/Packets/State/ResourceSnapshotPacket.cs b/Packets/State/ResourceSnapshotPacket.cs deleted file mode 100644 index e84800e..0000000 --- a/Packets/State/ResourceSnapshotPacket.cs +++ /dev/null @@ -1,37 +0,0 @@ -using KCM.StateManagement.Sync; -using System; -using System.Collections.Generic; - -namespace KCM.Packets.State -{ - public class ResourceSnapshotPacket : Packet - { - public override ushort packetId => (ushort)Enums.Packets.ResourceSnapshot; - - public override Riptide.MessageSendMode sendMode => Riptide.MessageSendMode.Unreliable; - - public List resourceTypes { get; set; } - public List amounts { get; set; } - - public override void HandlePacketClient() - { - try - { - if (KCClient.client.IsConnected && KCClient.client.Id == clientId) - return; - - SyncManager.ApplyResourceSnapshot(resourceTypes, amounts); - } - catch (Exception ex) - { - Main.helper.Log("Error applying ResourceSnapshotPacket"); - Main.helper.Log(ex.ToString()); - } - } - - public override void HandlePacketServer() - { - } - } -} - diff --git a/RiptideSteamTransport/LobbyManager.cs b/RiptideSteamTransport/LobbyManager.cs index 21e6b69..f159086 100644 --- a/RiptideSteamTransport/LobbyManager.cs +++ b/RiptideSteamTransport/LobbyManager.cs @@ -1,7 +1,6 @@ using KCM; using KCM.Enums; using KCM.Packets.Handlers; -using KCM.StateManagement.Observers; using Steamworks; using UnityEngine; @@ -154,7 +153,20 @@ namespace Riptide.Demos.Steam.PlayerHosted //NetworkManager.Singleton.StopServer(); //NetworkManager.Singleton.DisconnectClient(); SteamMatchmaking.LeaveLobby(lobbyId); - Main.ResetMultiplayerState("LeaveLobby"); + + if (KCClient.client.IsConnected) + KCClient.client.Disconnect(); + + Main.helper.Log("clear players"); + Main.kCPlayers.Clear(); + LobbyHandler.ClearPlayerList(); + LobbyHandler.ClearChatEntries(); + Main.helper.Log("end clear players"); + + if (KCServer.IsRunning) + KCServer.server.Stop(); + + Main.TransitionTo(MenuState.ServerBrowser); ServerBrowser.registerServer = false; diff --git a/ServerLobby/LobbyChat/ChatEntryScript.cs b/ServerLobby/LobbyChat/ChatEntryScript.cs index 77ddcab..4392924 100644 --- a/ServerLobby/LobbyChat/ChatEntryScript.cs +++ b/ServerLobby/LobbyChat/ChatEntryScript.cs @@ -51,24 +51,12 @@ namespace KCM.ServerLobby.LobbyChat { try { - if (banner == null) - return; - - string steamId; - if (!Main.clientSteamIds.TryGetValue(Client, out steamId)) - return; - KCPlayer player; - if (!Main.kCPlayers.TryGetValue(steamId, out player) || player == null) - return; + Main.kCPlayers.TryGetValue(Main.GetPlayerByClientID(Client).steamId, out player); - if (World.inst == null || World.inst.liverySets == null) - return; - - if (player.banner < 0 || player.banner >= World.inst.liverySets.Count) - return; - - banner.texture = World.inst.liverySets[player.banner].banners; + var bannerTexture = World.inst.liverySets[player.banner].banners; + + banner.texture = bannerTexture; } catch (Exception ex) { diff --git a/ServerLobby/PlayerEntryScript.cs b/ServerLobby/PlayerEntryScript.cs index 338984c..a564621 100644 --- a/ServerLobby/PlayerEntryScript.cs +++ b/ServerLobby/PlayerEntryScript.cs @@ -21,15 +21,15 @@ namespace KCM.ServerLobby public void Start() { - banner = transform.Find("PlayerBanner").GetComponent(); - SetValues(); InvokeRepeating("SetValues", 0, 0.25f); + banner = transform.Find("PlayerBanner").GetComponent(); + transform.Find("PlayerBanner").GetComponent