diff --git a/Enums/Packets.cs b/Enums/Packets.cs index 04eadfd..bc68b8c 100644 --- a/Enums/Packets.cs +++ b/Enums/Packets.cs @@ -47,6 +47,7 @@ namespace KCM.Enums PlaceKeepRandomly = 91, ResyncRequest = 92, ResourceSnapshot = 93, - BuildingSnapshot = 94 + BuildingSnapshot = 94, + VillagerSnapshot = 95 } } diff --git a/Packets/Game/GameVillager/VillagerSnapshotPacket.cs b/Packets/Game/GameVillager/VillagerSnapshotPacket.cs new file mode 100644 index 0000000..696890b --- /dev/null +++ b/Packets/Game/GameVillager/VillagerSnapshotPacket.cs @@ -0,0 +1,56 @@ +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/Handlers/PacketHandler.cs b/Packets/Handlers/PacketHandler.cs index 90a91ef..3226503 100644 --- a/Packets/Handlers/PacketHandler.cs +++ b/Packets/Handlers/PacketHandler.cs @@ -310,6 +310,27 @@ 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; @@ -543,6 +564,29 @@ 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/StateManagement/Sync/SyncManager.cs b/StateManagement/Sync/SyncManager.cs index 58404d5..9498098 100644 --- a/StateManagement/Sync/SyncManager.cs +++ b/StateManagement/Sync/SyncManager.cs @@ -16,9 +16,11 @@ namespace KCM.StateManagement.Sync private const int MaxBuildingSnapshotBytes = 30000; private const int MaxVillagerTeleportsPerResync = 400; private const int VillagerValidationIntervalMs = 10000; // 10 seconds + private const int VillagerSnapshotIntervalMs = 1000; private static long lastResourceBroadcastMs; private static long lastVillagerValidationMs; + private static long lastVillagerSnapshotMs; private static FieldInfo freeResourceAmountField; private static MethodInfo resourceAmountGetMethod; @@ -63,6 +65,20 @@ namespace KCM.StateManagement.Sync lastVillagerValidationMs = now; ValidateAndCorrectVillagerStates(); } + + if ((now - lastVillagerSnapshotMs) >= VillagerSnapshotIntervalMs) + { + lastVillagerSnapshotMs = now; + try + { + BroadcastVillagerSnapshot(); + } + catch (Exception ex) + { + Main.helper.Log("Error broadcasting villager snapshot"); + Main.helper.Log(ex.ToString()); + } + } } public static void SendResyncToClient(ushort toClient, string reason) @@ -559,6 +575,44 @@ namespace KCM.StateManagement.Sync } } + private static void BroadcastVillagerSnapshot() + { + if (!KCServer.IsRunning) + return; + + if (KCServer.server.ClientCount == 0) + return; + + if (Villager.villagers == null || Villager.villagers.Count == 0) + return; + + List guids = new List(); + List positions = new List(); + const int maxVillagersPerSnapshot = 200; + + for (int i = 0; i < Villager.villagers.Count && guids.Count < maxVillagersPerSnapshot; i++) + { + Villager villager = Villager.villagers.data[i]; + if (villager == null) + continue; + + guids.Add(villager.guid); + positions.Add(villager.Pos); + } + + if (guids.Count == 0) + return; + + VillagerSnapshotPacket snapshot = new VillagerSnapshotPacket + { + guids = guids, + positions = positions + }; + + ushort exceptId = KCClient.client != null ? KCClient.client.Id : (ushort)0; + snapshot.SendToAll(exceptId); + } + public static void ApplyResourceSnapshot(List resourceTypes, List amounts) { if (resourceTypes == null || amounts == null)