network fix
This commit is contained in:
14
KCClient.cs
14
KCClient.cs
@@ -76,7 +76,19 @@ 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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
68
KCServer.cs
68
KCServer.cs
@@ -21,6 +21,9 @@ namespace KCM
|
||||
public static Server server = new Server(Main.steamServer);
|
||||
public static bool started = false;
|
||||
|
||||
private static readonly Dictionary<ushort, Queue<SaveTransferPacket>> saveTransferQueues = new Dictionary<ushort, Queue<SaveTransferPacket>>();
|
||||
private const int SaveTransferPacketsPerUpdatePerClient = 10;
|
||||
|
||||
static KCServer()
|
||||
{
|
||||
//server.registerMessageHandler(typeof(KCServer).GetMethod("ClientJoined"));
|
||||
@@ -50,6 +53,7 @@ namespace KCM
|
||||
}
|
||||
|
||||
ev.Client.CanQualityDisconnect = false;
|
||||
ev.Client.MaxSendAttempts = 50;
|
||||
|
||||
Main.helper.Log("Client ID is: " + ev.Client.Id);
|
||||
|
||||
@@ -85,6 +89,8 @@ namespace KCM
|
||||
if (entry != null)
|
||||
Destroy(entry.gameObject);
|
||||
|
||||
saveTransferQueues.Remove(ev.Client.Id);
|
||||
|
||||
Main.helper.Log($"Client disconnected. {ev.Reason}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -125,6 +131,68 @@ namespace KCM
|
||||
private void Update()
|
||||
{
|
||||
server.Update();
|
||||
ProcessSaveTransfers();
|
||||
}
|
||||
|
||||
private static void ProcessSaveTransfers()
|
||||
{
|
||||
if (!KCServer.IsRunning)
|
||||
return;
|
||||
|
||||
if (saveTransferQueues.Count == 0)
|
||||
return;
|
||||
|
||||
var clients = saveTransferQueues.Keys.ToList();
|
||||
foreach (var clientId in clients)
|
||||
{
|
||||
Queue<SaveTransferPacket> 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<SaveTransferPacket>(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()
|
||||
|
||||
34
Main.cs
34
Main.cs
@@ -55,6 +55,8 @@ namespace KCM
|
||||
public static Dictionary<string, KCPlayer> kCPlayers = new Dictionary<string, KCPlayer>();
|
||||
public static Dictionary<ushort, string> clientSteamIds = new Dictionary<ushort, string>();
|
||||
|
||||
private static readonly Dictionary<int, long> lastTeamIdLookupLogMs = new Dictionary<int, long>();
|
||||
|
||||
public static KCPlayer GetPlayerByClientID(ushort clientId)
|
||||
{
|
||||
return kCPlayers[clientSteamIds[clientId]];
|
||||
@@ -62,23 +64,33 @@ namespace KCM
|
||||
|
||||
public static Player GetPlayerByTeamID(int teamId) // Need to replace building / production types so that the correct player is used. IResourceStorage and IResourceProvider, and jobs
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = kCPlayers.Values.FirstOrDefault(p => p.inst.PlayerLandmassOwner.teamId == teamId).inst;
|
||||
KCPlayer match = kCPlayers.Values.FirstOrDefault(p =>
|
||||
p != null &&
|
||||
p.inst != null &&
|
||||
p.inst.PlayerLandmassOwner != null &&
|
||||
p.inst.PlayerLandmassOwner.teamId == teamId);
|
||||
|
||||
return player;
|
||||
}
|
||||
catch (Exception e)
|
||||
if (match != null && match.inst != null)
|
||||
return match.inst;
|
||||
|
||||
if (KCServer.IsRunning || KCClient.client.IsConnected)
|
||||
{
|
||||
if (KCServer.IsRunning || KCClient.client.IsConnected)
|
||||
long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
||||
long last;
|
||||
if (!lastTeamIdLookupLogMs.TryGetValue(teamId, out last) || (now - last) > 2000)
|
||||
{
|
||||
Main.helper.Log("Failed finding player by teamID: " + teamId + " My teamID is: " + Player.inst.PlayerLandmassOwner.teamId);
|
||||
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(kCPlayers.Count.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);
|
||||
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())));
|
||||
}
|
||||
}
|
||||
|
||||
return Player.inst;
|
||||
}
|
||||
|
||||
|
||||
@@ -222,7 +222,13 @@ namespace KCM.Packets.Handlers
|
||||
try
|
||||
{
|
||||
var packetRef = Packets[packet.packetId];
|
||||
Message message = Message.Create(MessageSendMode.Reliable, packet.packetId);
|
||||
|
||||
MessageSendMode sendMode = MessageSendMode.Reliable;
|
||||
Packet basePacket = packet as Packet;
|
||||
if (basePacket != null)
|
||||
sendMode = basePacket.sendMode;
|
||||
|
||||
Message message = Message.Create(sendMode, packet.packetId);
|
||||
|
||||
foreach (var prop in packetRef.properties)
|
||||
{
|
||||
|
||||
@@ -92,36 +92,7 @@ namespace KCM.Packets.Network
|
||||
return;
|
||||
|
||||
byte[] bytes = LoadSaveLoadAtPathHook.saveData;
|
||||
int chunkSize = 900; // 900 bytes per chunk to fit within packet size limit
|
||||
|
||||
List<byte[]> 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");
|
||||
KCServer.EnqueueSaveTransfer(clientId, bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace KCM.Packets
|
||||
{
|
||||
public abstract ushort packetId { get; }
|
||||
public ushort clientId { get; set; }
|
||||
public virtual Riptide.MessageSendMode sendMode => Riptide.MessageSendMode.Reliable;
|
||||
|
||||
public KCPlayer player
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ 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; }
|
||||
|
||||
@@ -23,6 +23,9 @@ A mellékelt log (`output.txt`) alapján több tipikus hiba okozta a szerver ind
|
||||
- Mentés betöltéskor a `ProcessBuilding` útvonal kiegészítése `World.inst.PlaceFromLoad(...)` + `UnpackStage2(...)` hívásokkal (különösen fontos a “világba helyezés” mellékhatásai miatt, pl. farm/field regisztráció)
|
||||
- Save transfer kliens oldalon robusztusabb inicializálás/reset (ne ragadjon be a statikus állapot több betöltés után, plusz bounds/null ellenőrzések)
|
||||
- Kompatibilitási fix: `World.inst.liverySets` lista esetén `.Count` használata `.Length` helyett (különben `Compilation failed` lehet egyes verziókon)
|
||||
- Hálózati stabilitás: `BuildingStatePacket` most `Unreliable` módban megy (state jellegű csomagoknál jobb, ha a legfrissebb állapot érkezik meg és nem torlódik fel a megbízható sor)
|
||||
- Mentés-szinkron stabilitás: szerver oldalon a save chunkok már nem egy nagy for-ciklusban mennek ki, hanem ütemezve (csökkenti a “The gap between received sequence IDs…” / “Poor connection” diszkonnekteket)
|
||||
- Kapcsolat tuning: kliens és szerver oldalon emelt `MaxSendAttempts`, és tiltott minőség-alapú auto-disconnect (különösen save transfer közben volt agresszív)
|
||||
|
||||
Érintett fájlok (főbb pontok):
|
||||
|
||||
@@ -36,6 +39,8 @@ A mellékelt log (`output.txt`) alapján több tipikus hiba okozta a szerver ind
|
||||
- `KCServer.cs`
|
||||
- `Packets/Handlers/LobbyHandler.cs`
|
||||
- `RiptideSteamTransport/LobbyManager.cs`
|
||||
- `Packets/Handlers/PacketHandler.cs`
|
||||
- `Packets/State/BuildingStatePacket.cs`
|
||||
|
||||
## Telepítés / használat
|
||||
|
||||
|
||||
Reference in New Issue
Block a user