Rolled back ServerEntityEventManager
This commit is contained in:
+44
-99
@@ -1,12 +1,8 @@
|
|||||||
using Barotrauma.Extensions;
|
using Barotrauma.Extensions;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using static Barotrauma.EosInterface.Ownership;
|
|
||||||
|
|
||||||
namespace Barotrauma.Networking
|
namespace Barotrauma.Networking
|
||||||
{
|
{
|
||||||
@@ -48,8 +44,6 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
class ServerEntityEventManager : NetEntityEventManager
|
class ServerEntityEventManager : NetEntityEventManager
|
||||||
{
|
{
|
||||||
static public ServerEntityEventManager SEM;
|
|
||||||
|
|
||||||
private readonly List<ServerEntityEvent> events;
|
private readonly List<ServerEntityEvent> events;
|
||||||
|
|
||||||
//list of unique events (i.e. !IsDuplicate) created during the round
|
//list of unique events (i.e. !IsDuplicate) created during the round
|
||||||
@@ -108,20 +102,6 @@ namespace Barotrauma.Networking
|
|||||||
private readonly GameServer server;
|
private readonly GameServer server;
|
||||||
|
|
||||||
private double lastEventCountHighWarning;
|
private double lastEventCountHighWarning;
|
||||||
private class PendingCreateEvent
|
|
||||||
{
|
|
||||||
public IServerSerializable Entity;
|
|
||||||
public NetEntityEvent.IData Data;
|
|
||||||
public PendingCreateEvent(IServerSerializable entity, NetEntityEvent.IData data)
|
|
||||||
{
|
|
||||||
Entity = entity;
|
|
||||||
Data = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly ConcurrentQueue<PendingCreateEvent> pendingCreateQueue;
|
|
||||||
|
|
||||||
private readonly Task createEventTask;
|
|
||||||
|
|
||||||
public ServerEntityEventManager(GameServer server)
|
public ServerEntityEventManager(GameServer server)
|
||||||
{
|
{
|
||||||
@@ -133,86 +113,51 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
uniqueEvents = new List<ServerEntityEvent>();
|
uniqueEvents = new List<ServerEntityEvent>();
|
||||||
|
|
||||||
pendingCreateQueue = new ConcurrentQueue<PendingCreateEvent>();
|
|
||||||
|
|
||||||
lastWarningTime = -10.0;
|
lastWarningTime = -10.0;
|
||||||
|
|
||||||
SEM = this;
|
|
||||||
|
|
||||||
createEventTask = Task.Run(async () => await CreateEventProcessorLoop());
|
|
||||||
}
|
|
||||||
private Task CreateEventProcessorLoop()
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
ProcessPendingCreateEvents();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessPendingCreateEvents()
|
|
||||||
{
|
|
||||||
// Dequeue and process all pending events currently in the queue.
|
|
||||||
// Use a lock to synchronize modifications to shared lists / ID.
|
|
||||||
while (pendingCreateQueue.TryDequeue(out PendingCreateEvent pending))
|
|
||||||
{
|
|
||||||
// The original CreateEvent logic (mostly unchanged) but executed under a lock
|
|
||||||
if (pending == null || pending.Entity == null) { continue; }
|
|
||||||
|
|
||||||
var entity = pending.Entity;
|
|
||||||
var extraData = pending.Data;
|
|
||||||
|
|
||||||
var newEvent = new ServerEntityEvent(entity, (UInt16)(ID + 1));
|
|
||||||
if (extraData != null) newEvent.SetData(extraData);
|
|
||||||
|
|
||||||
bool inGameClientsPresent = server.ConnectedClients.Count(c => c.InGame) > 0;
|
|
||||||
//remove old events that have been sent to all clients, they are redundant now
|
|
||||||
// keep at least one event in the list (lastSentToAll == e.ID) so we can use it to keep track of the latest ID
|
|
||||||
// and events less than 15 seconds old to give disconnected clients a bit of time to reconnect without getting desynced
|
|
||||||
if (GameMain.GameSession.RoundDuration > server.ServerSettings.RoundStartSyncDuration)
|
|
||||||
{
|
|
||||||
events.RemoveAll(e =>
|
|
||||||
(NetIdUtils.IdMoreRecent(lastSentToAll, e.ID) || !inGameClientsPresent) &&
|
|
||||||
e.CreateTime < Timing.TotalTime - server.ServerSettings.EventRemovalTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool duplicateFound = false;
|
|
||||||
for (int i = events.Count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
//we already have an identical event that's waiting to be sent
|
|
||||||
// -> no need to add a new one
|
|
||||||
if (events[i].IsDuplicate(newEvent) && !events[i].Sent)
|
|
||||||
{
|
|
||||||
duplicateFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (duplicateFound) { continue; }
|
|
||||||
|
|
||||||
ID++;
|
|
||||||
|
|
||||||
events.Add(newEvent);
|
|
||||||
|
|
||||||
if (!uniqueEvents.Any(e => e.IsDuplicate(newEvent)))
|
|
||||||
{
|
|
||||||
//create a copy of the event and give it a new ID
|
|
||||||
var uniqueEvent = new ServerEntityEvent(entity, (UInt16)(uniqueEvents.Count + 1));
|
|
||||||
uniqueEvent.SetData(extraData);
|
|
||||||
|
|
||||||
uniqueEvents.Add(uniqueEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void CreateEvent(IServerSerializable entity, NetEntityEvent.IData extraData = null)
|
public void CreateEvent(IServerSerializable entity, NetEntityEvent.IData extraData = null)
|
||||||
{
|
{
|
||||||
if (!ValidateEntity(entity)) { return; }
|
if (!ValidateEntity(entity)) { return; }
|
||||||
|
|
||||||
// enqueue and let background task handle the rest
|
var newEvent = new ServerEntityEvent(entity, (UInt16)(ID + 1));
|
||||||
pendingCreateQueue.Enqueue(new PendingCreateEvent(entity, extraData));
|
if (extraData != null) newEvent.SetData(extraData);
|
||||||
|
|
||||||
|
bool inGameClientsPresent = server.ConnectedClients.Count(c => c.InGame) > 0;
|
||||||
|
|
||||||
|
//remove old events that have been sent to all clients, they are redundant now
|
||||||
|
// keep at least one event in the list (lastSentToAll == e.ID) so we can use it to keep track of the latest ID
|
||||||
|
// and events less than 15 seconds old to give disconnected clients a bit of time to reconnect without getting desynced
|
||||||
|
if (GameMain.GameSession.RoundDuration > server.ServerSettings.RoundStartSyncDuration)
|
||||||
|
{
|
||||||
|
events.RemoveAll(e =>
|
||||||
|
(NetIdUtils.IdMoreRecent(lastSentToAll, e.ID) || !inGameClientsPresent) &&
|
||||||
|
e.CreateTime < Timing.TotalTime - server.ServerSettings.EventRemovalTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = events.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
//we already have an identical event that's waiting to be sent
|
||||||
|
// -> no need to add a new one
|
||||||
|
if (events[i].IsDuplicate(newEvent) && !events[i].Sent) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ID++;
|
||||||
|
|
||||||
|
events.Add(newEvent);
|
||||||
|
|
||||||
|
if (!uniqueEvents.Any(e => e.IsDuplicate(newEvent)))
|
||||||
|
{
|
||||||
|
//create a copy of the event and give it a new ID
|
||||||
|
var uniqueEvent = new ServerEntityEvent(entity, (UInt16)(uniqueEvents.Count + 1));
|
||||||
|
uniqueEvent.SetData(extraData);
|
||||||
|
|
||||||
|
uniqueEvents.Add(uniqueEvent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(List<Client> clients)
|
public void Update(List<Client> clients)
|
||||||
{
|
{
|
||||||
|
|
||||||
foreach (BufferedEvent bufferedEvent in bufferedEvents)
|
foreach (BufferedEvent bufferedEvent in bufferedEvents)
|
||||||
{
|
{
|
||||||
if (bufferedEvent.Character == null || bufferedEvent.Character.IsDead)
|
if (bufferedEvent.Character == null || bufferedEvent.Character.IsDead)
|
||||||
@@ -306,15 +251,15 @@ namespace Barotrauma.Networking
|
|||||||
NetIdUtils.IdMoreRecent((UInt16)(lastSentToAll + 1), c.LastRecvEntityEventID) &&
|
NetIdUtils.IdMoreRecent((UInt16)(lastSentToAll + 1), c.LastRecvEntityEventID) &&
|
||||||
(firstEventToResend.CreateTime > c.MidRoundSyncTimeOut || lastSentToAnyoneTime > c.MidRoundSyncTimeOut || Timing.TotalTime > c.MidRoundSyncTimeOut + 10.0));
|
(firstEventToResend.CreateTime > c.MidRoundSyncTimeOut || lastSentToAnyoneTime > c.MidRoundSyncTimeOut || Timing.TotalTime > c.MidRoundSyncTimeOut + 10.0));
|
||||||
toKick.ForEach(c =>
|
toKick.ForEach(c =>
|
||||||
{
|
{
|
||||||
DebugConsole.NewMessage(c.Name + " was kicked because they were expecting a very old network event (" + (c.LastRecvEntityEventID + 1).ToString() + ")", Color.Red);
|
DebugConsole.NewMessage(c.Name + " was kicked because they were expecting a very old network event (" + (c.LastRecvEntityEventID + 1).ToString() + ")", Color.Red);
|
||||||
GameServer.Log(GameServer.ClientLogName(c) + " was kicked because they were expecting a very old network event ("
|
GameServer.Log(GameServer.ClientLogName(c) + " was kicked because they were expecting a very old network event ("
|
||||||
+ (c.LastRecvEntityEventID + 1).ToString() +
|
+ (c.LastRecvEntityEventID + 1).ToString() +
|
||||||
" (created " + (Timing.TotalTime - firstEventToResend.CreateTime).ToString("0.##") + " s ago, " +
|
" (created " + (Timing.TotalTime - firstEventToResend.CreateTime).ToString("0.##") + " s ago, " +
|
||||||
(lastSentToAnyoneTime - firstEventToResend.CreateTime).ToString("0.##") + " s older than last event sent to anyone)" +
|
(lastSentToAnyoneTime - firstEventToResend.CreateTime).ToString("0.##") + " s older than last event sent to anyone)" +
|
||||||
" Events queued: " + events.Count + ", last sent to all: " + lastSentToAll, ServerLog.MessageType.Error);
|
" Events queued: " + events.Count + ", last sent to all: " + lastSentToAll, ServerLog.MessageType.Error);
|
||||||
server.DisconnectClient(c, PeerDisconnectPacket.WithReason(DisconnectReason.ExcessiveDesyncOldEvent));
|
server.DisconnectClient(c, PeerDisconnectPacket.WithReason(DisconnectReason.ExcessiveDesyncOldEvent));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user