Some classes for syncing entity state changes. Similar to the NetworkEvents in the old netcode, but the logic is split into separate classes which prevent the server from reading updates for entities that aren't IClientSerializable.
todo: add NetEntityEventManagers to server & client, some logic to prevent sending events that don't need to be sent (e.g. duplicate event state updates)
This commit is contained in:
@@ -157,7 +157,10 @@
|
||||
<Compile Include="Source\Networking\INetSerializable.cs" />
|
||||
<Compile Include="Source\Networking\NetBufferExtensions.cs" />
|
||||
<Compile Include="Source\Networking\NetConfig.cs" />
|
||||
<Compile Include="Source\Networking\NetEntityEvent\NetEntityEvent.cs" />
|
||||
<Compile Include="Source\Networking\NetEntityEvent\NetEntityEventManager.cs" />
|
||||
<Compile Include="Source\Networking\NetStats.cs" />
|
||||
<Compile Include="Source\Networking\ServerEntityEvent.cs" />
|
||||
<Compile Include="Source\Networking\RespawnManager.cs" />
|
||||
<Compile Include="Source\Networking\ServerLog.cs" />
|
||||
<Compile Include="Source\Networking\WhiteList.cs" />
|
||||
|
||||
@@ -1911,7 +1911,7 @@ namespace Barotrauma
|
||||
if (AnimController != null) AnimController.Remove();
|
||||
}
|
||||
|
||||
public virtual void ClientWrite(NetOutgoingMessage msg)
|
||||
public virtual void ClientWrite(NetBuffer msg)
|
||||
{
|
||||
if (GameMain.Server != null) return;
|
||||
|
||||
@@ -1972,7 +1972,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ServerWrite(NetOutgoingMessage msg, Client c)
|
||||
public virtual void ServerWrite(NetBuffer msg, Client c)
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
|
||||
@@ -2037,7 +2037,7 @@ namespace Barotrauma
|
||||
memPos.Insert(index, posInfo);
|
||||
}
|
||||
|
||||
public void WriteSpawnData(NetOutgoingMessage msg)
|
||||
public void WriteSpawnData(NetBuffer msg)
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
|
||||
|
||||
@@ -648,7 +648,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void ServerWrite(Lidgren.Network.NetOutgoingMessage msg, Barotrauma.Networking.Client c)
|
||||
public override void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
|
||||
{
|
||||
msg.Write(docked);
|
||||
|
||||
|
||||
@@ -493,7 +493,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void ServerWrite(Lidgren.Network.NetOutgoingMessage msg, Barotrauma.Networking.Client c)
|
||||
public override void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
|
||||
{
|
||||
msg.Write(isOpen);
|
||||
msg.WriteRangedSingle(stuck, 0.0f, 100.0f, 8);
|
||||
|
||||
@@ -662,10 +662,10 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ClientWrite(NetOutgoingMessage msg) { }
|
||||
public virtual void ClientWrite(NetBuffer msg) { }
|
||||
public virtual void ServerRead(NetIncomingMessage msg, Client c) { }
|
||||
|
||||
public virtual void ServerWrite(NetOutgoingMessage msg, Client c) { }
|
||||
public virtual void ServerWrite(NetBuffer msg, Client c) { }
|
||||
public virtual void ClientRead(NetIncomingMessage msg, float sendingTime) { }
|
||||
|
||||
public virtual XElement Save(XElement parentElement)
|
||||
|
||||
@@ -196,7 +196,7 @@ namespace Barotrauma.Items.Components
|
||||
if (!IsActive) currPowerConsumption = 0.0f;
|
||||
}
|
||||
|
||||
public override void ClientWrite(Lidgren.Network.NetOutgoingMessage msg)
|
||||
public override void ClientWrite(Lidgren.Network.NetBuffer msg)
|
||||
{
|
||||
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
|
||||
msg.WriteRangedInteger(-10, 10, (int)(flowPercentage / 10.0f));
|
||||
@@ -209,7 +209,7 @@ namespace Barotrauma.Items.Components
|
||||
IsActive = msg.ReadBoolean();
|
||||
}
|
||||
|
||||
public override void ServerWrite(Lidgren.Network.NetOutgoingMessage msg, Barotrauma.Networking.Client c)
|
||||
public override void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
|
||||
{
|
||||
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
|
||||
msg.WriteRangedInteger(-10, 10, (int)(flowPercentage / 10.0f));
|
||||
|
||||
@@ -411,7 +411,7 @@ namespace Barotrauma.Items.Components
|
||||
if (screenOverlay != null) screenOverlay.Remove();
|
||||
}
|
||||
|
||||
public override void ClientWrite(Lidgren.Network.NetOutgoingMessage msg)
|
||||
public override void ClientWrite(Lidgren.Network.NetBuffer msg)
|
||||
{
|
||||
msg.Write(IsActive);
|
||||
}
|
||||
@@ -422,7 +422,7 @@ namespace Barotrauma.Items.Components
|
||||
isActiveTickBox.Selected = IsActive;
|
||||
}
|
||||
|
||||
public override void ServerWrite(Lidgren.Network.NetOutgoingMessage msg, Barotrauma.Networking.Client c)
|
||||
public override void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
|
||||
{
|
||||
msg.Write(IsActive);
|
||||
}
|
||||
|
||||
@@ -538,7 +538,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void ClientWrite(NetOutgoingMessage msg)
|
||||
public override void ClientWrite(NetBuffer msg)
|
||||
{
|
||||
msg.Write(autoTemp);
|
||||
msg.WriteRangedSingle(shutDownTemp, 0.0f, 10000.0f, 8);
|
||||
@@ -556,7 +556,7 @@ namespace Barotrauma.Items.Components
|
||||
FissionRate = msg.ReadRangedSingle(0.0f, 100.0f, 8);
|
||||
}
|
||||
|
||||
public override void ServerWrite(NetOutgoingMessage msg, Client c)
|
||||
public override void ServerWrite(NetBuffer msg, Client c)
|
||||
{
|
||||
msg.WriteRangedSingle(temperature, 0.0f, 10000.0f, 16);
|
||||
|
||||
|
||||
@@ -443,7 +443,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void ClientWrite(Lidgren.Network.NetOutgoingMessage msg)
|
||||
public override void ClientWrite(Lidgren.Network.NetBuffer msg)
|
||||
{
|
||||
msg.Write(autoPilot);
|
||||
|
||||
@@ -503,7 +503,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void ServerWrite(Lidgren.Network.NetOutgoingMessage msg, Barotrauma.Networking.Client c)
|
||||
public override void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
|
||||
{
|
||||
msg.Write(autoPilot);
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ namespace Barotrauma.Items.Components
|
||||
GuiFrame.Update(1.0f / 60.0f);
|
||||
}
|
||||
|
||||
public override void ClientWrite(Lidgren.Network.NetOutgoingMessage msg)
|
||||
public override void ClientWrite(Lidgren.Network.NetBuffer msg)
|
||||
{
|
||||
float chargeSpeed = MathHelper.Clamp(rechargeSpeed / MaxRechargeSpeed, 0.0f, 1.0f);
|
||||
msg.WriteRangedSingle(chargeSpeed, 0.0f, 1.0f, 8);
|
||||
@@ -260,7 +260,7 @@ namespace Barotrauma.Items.Components
|
||||
RechargeSpeed = msg.ReadRangedSingle(0.0f, 1.0f, 8) * maxRechargeSpeed;
|
||||
}
|
||||
|
||||
public override void ServerWrite(Lidgren.Network.NetOutgoingMessage msg, Barotrauma.Networking.Client c)
|
||||
public override void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
|
||||
{
|
||||
float chargeSpeed = MathHelper.Clamp(rechargeSpeed / MaxRechargeSpeed, 0.0f, 1.0f);
|
||||
msg.WriteRangedSingle(chargeSpeed, 0.0f, 1.0f, 8);
|
||||
|
||||
@@ -532,7 +532,7 @@ namespace Barotrauma.Items.Components
|
||||
base.RemoveComponentSpecific();
|
||||
}
|
||||
|
||||
public override void ClientWrite(Lidgren.Network.NetOutgoingMessage msg)
|
||||
public override void ClientWrite(Lidgren.Network.NetBuffer msg)
|
||||
{
|
||||
msg.Write((byte)Math.Min(Nodes.Count, 255));
|
||||
for (int i = 0; i < Math.Min(Nodes.Count, 255); i++)
|
||||
|
||||
@@ -1579,11 +1579,11 @@ namespace Barotrauma
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public void ServerWrite(NetOutgoingMessage msg, Client c) { }
|
||||
|
||||
public void ServerWrite(NetBuffer msg, Client c) { }
|
||||
public void ClientRead(NetIncomingMessage msg, float sendingTime) { }
|
||||
|
||||
public void WriteSpawnData(NetOutgoingMessage msg)
|
||||
public void WriteSpawnData(NetBuffer msg)
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
|
||||
|
||||
@@ -845,7 +845,7 @@ namespace Barotrauma
|
||||
return newBody;
|
||||
}
|
||||
|
||||
public void ServerWrite(NetOutgoingMessage msg, Client c)
|
||||
public void ServerWrite(NetBuffer msg, Client c)
|
||||
{
|
||||
for (int i = 0; i < sections.Length; i++)
|
||||
{
|
||||
|
||||
@@ -1163,7 +1163,7 @@ namespace Barotrauma
|
||||
DockedTo.Clear();
|
||||
}
|
||||
|
||||
public void ServerWrite(NetOutgoingMessage msg, Client c)
|
||||
public void ServerWrite(NetBuffer msg, Client c)
|
||||
{
|
||||
msg.Write(ID);
|
||||
//length in bytes
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Barotrauma.Networking
|
||||
public bool hasLobbyData = false;
|
||||
public UInt32 lastSentChatMsgID = 0; //last msg this client said
|
||||
public UInt32 lastRecvChatMsgID = 0; //last msg this client knows about
|
||||
public UInt32 lastRecvEntityEventID = 0;
|
||||
|
||||
public UInt32 lastRecvEntitySpawnID = 0;
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ namespace Barotrauma
|
||||
NetStateID = (UInt32)spawnHistory.Count;
|
||||
}
|
||||
|
||||
public void ServerWrite(Lidgren.Network.NetOutgoingMessage message, Client client)
|
||||
public void ServerWrite(Lidgren.Network.NetBuffer message, Client client)
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace Barotrauma.Networking
|
||||
private UInt32 lastQueueChatMsgID = 0; //last message added to the queue
|
||||
private List<ChatMessage> chatMsgQueue = new List<ChatMessage>();
|
||||
|
||||
public UInt32 LastSentEntityEventID;
|
||||
|
||||
public byte ID
|
||||
{
|
||||
get { return myID; }
|
||||
|
||||
@@ -3,25 +3,27 @@ using Lidgren.Network;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
interface INetSerializable { }
|
||||
|
||||
/// <summary>
|
||||
/// Interface for entities that the clients can send information of to the server
|
||||
/// </summary>
|
||||
interface IClientSerializable
|
||||
interface IClientSerializable : INetSerializable
|
||||
{
|
||||
UInt32 NetStateID { get; }
|
||||
|
||||
void ClientWrite(NetOutgoingMessage msg);
|
||||
void ClientWrite(NetBuffer msg);
|
||||
void ServerRead(NetIncomingMessage msg, Client c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for entities that the server can send information of to the clients
|
||||
/// </summary>
|
||||
interface IServerSerializable
|
||||
interface IServerSerializable : INetSerializable
|
||||
{
|
||||
UInt32 NetStateID { get; }
|
||||
|
||||
void ServerWrite(NetOutgoingMessage msg, Client c);
|
||||
void ServerWrite(NetBuffer msg, Client c);
|
||||
void ClientRead(NetIncomingMessage msg, float sendingTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class ClientEntityEventManager : NetEntityEventManager
|
||||
{
|
||||
private List<ClientEntityEvent> events;
|
||||
|
||||
private UInt32 ID;
|
||||
|
||||
private GameClient thisClient;
|
||||
|
||||
public ClientEntityEventManager(GameClient client) { }
|
||||
|
||||
public void CreateEvent(IClientSerializable entity)
|
||||
{
|
||||
if (!(entity is Entity))
|
||||
{
|
||||
DebugConsole.ThrowError("Can't create an entity event for " + entity + "!");
|
||||
return;
|
||||
}
|
||||
|
||||
ID++;
|
||||
events.Add(new ClientEntityEvent(entity, ID));
|
||||
}
|
||||
|
||||
public void Write(NetOutgoingMessage msg)
|
||||
{
|
||||
var eventsToSync = events.SkipWhile(e => e.ID >= thisClient.LastSentEntityEventID).ToList();
|
||||
if (eventsToSync.Count == 0) return;
|
||||
|
||||
Write(msg, eventsToSync.Cast<NetEntityEvent>().ToList());
|
||||
}
|
||||
|
||||
protected override void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
|
||||
{
|
||||
var clientEvent = entityEvent as ClientEntityEvent;
|
||||
if (clientEvent == null) return;
|
||||
|
||||
clientEvent.Write(buffer);
|
||||
}
|
||||
|
||||
protected override void ReadEvent(NetIncomingMessage buffer, INetSerializable entity, float sendingTime, Client sender = null)
|
||||
{
|
||||
var clientEntity = entity as IClientSerializable;
|
||||
if (clientEntity == null) return;
|
||||
|
||||
clientEntity.ServerRead(buffer, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
abstract class NetEntityEvent
|
||||
{
|
||||
public readonly Entity Entity;
|
||||
public readonly UInt32 ID;
|
||||
|
||||
protected NetEntityEvent(INetSerializable entity, UInt32 id)
|
||||
{
|
||||
this.ID = id;
|
||||
this.Entity = entity as Entity;
|
||||
}
|
||||
}
|
||||
|
||||
class ServerEntityEvent : NetEntityEvent
|
||||
{
|
||||
private IServerSerializable serializable;
|
||||
|
||||
public ServerEntityEvent(IServerSerializable entity, UInt32 id)
|
||||
: base(entity, id)
|
||||
{
|
||||
serializable = entity;
|
||||
}
|
||||
|
||||
public void Write(NetBuffer msg, Client recipient)
|
||||
{
|
||||
serializable.ServerWrite(msg, recipient);
|
||||
}
|
||||
}
|
||||
|
||||
class ClientEntityEvent : NetEntityEvent
|
||||
{
|
||||
private IClientSerializable serializable;
|
||||
|
||||
public ClientEntityEvent(IClientSerializable entity, UInt32 id)
|
||||
: base(entity, id)
|
||||
{
|
||||
serializable = entity;
|
||||
}
|
||||
|
||||
public void Write(NetBuffer msg)
|
||||
{
|
||||
serializable.ClientWrite(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
abstract class NetEntityEventManager
|
||||
{
|
||||
const int MaxEventsPerWrite = 255;
|
||||
|
||||
private UInt32 lastReceivedEntityEventID;
|
||||
|
||||
/// <summary>
|
||||
/// Write the events to the outgoing message. The recipient parameter is only needed for ServerEntityEventManager
|
||||
/// </summary>
|
||||
protected void Write(NetOutgoingMessage msg, List<NetEntityEvent> eventsToSync, Client recipient = null)
|
||||
{
|
||||
//too many events for one packet
|
||||
if (eventsToSync.Count > MaxEventsPerWrite)
|
||||
{
|
||||
eventsToSync.RemoveRange(MaxEventsPerWrite, eventsToSync.Count - MaxEventsPerWrite);
|
||||
}
|
||||
|
||||
msg.Write((byte)ServerNetObject.ENTITY_STATE);
|
||||
|
||||
msg.Write(eventsToSync[0].ID);
|
||||
msg.Write((byte)eventsToSync.Count);
|
||||
|
||||
foreach (NetEntityEvent e in eventsToSync)
|
||||
{
|
||||
//write into a temporary buffer so we can write the length before the actual data
|
||||
NetBuffer tempBuffer = new NetBuffer();
|
||||
WriteEvent(tempBuffer, e, recipient);
|
||||
tempBuffer.WritePadBits();
|
||||
|
||||
Debug.Assert(
|
||||
tempBuffer.LengthBytes < 256,
|
||||
"Maximum EntityEvent size exceeded when serializing \""+e.Entity+"\"!");
|
||||
|
||||
msg.Write((UInt16)e.Entity.ID);
|
||||
msg.Write((byte)tempBuffer.LengthBytes);
|
||||
msg.Write(tempBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the events from the message, ignoring ones we've already received
|
||||
/// </summary>
|
||||
public void Read(NetIncomingMessage msg, float sendingTime)
|
||||
{
|
||||
UInt32 firstEventID = msg.ReadUInt32();
|
||||
byte eventCount = msg.ReadByte();
|
||||
|
||||
for (int i = 0; i < eventCount; i++)
|
||||
{
|
||||
UInt32 thisEventID = firstEventID + (UInt32)i;
|
||||
UInt16 entityID = msg.ReadUInt16();
|
||||
byte msgLength = msg.ReadByte();
|
||||
|
||||
INetSerializable entity = Entity.FindEntityByID(entityID) as INetSerializable;
|
||||
|
||||
//skip the event if we've already received it or if the entity isn't found
|
||||
if (thisEventID <= lastReceivedEntityEventID || entity == null)
|
||||
{
|
||||
msg.Position += msgLength * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadEvent(msg, entity, sendingTime);
|
||||
lastReceivedEntityEventID = thisEventID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void ReadEvent(NetIncomingMessage buffer, INetSerializable entity, float sendingTime, Client sender = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class ServerEntityEventManager : NetEntityEventManager
|
||||
{
|
||||
private List<ServerEntityEvent> events;
|
||||
|
||||
private UInt32 ID;
|
||||
|
||||
public ServerEntityEventManager(GameServer server) { }
|
||||
|
||||
public void CreateEvent(IServerSerializable entity)
|
||||
{
|
||||
if (!(entity is Entity))
|
||||
{
|
||||
DebugConsole.ThrowError("Can't create an entity event for " + entity + "!");
|
||||
return;
|
||||
}
|
||||
|
||||
ID++;
|
||||
events.Add(new ServerEntityEvent(entity, ID));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes all the events that the client hasn't received yet into the outgoing message
|
||||
/// </summary>
|
||||
public void Write(Client client, NetOutgoingMessage msg)
|
||||
{
|
||||
var eventsToSync = events.SkipWhile(e => e.ID >= client.lastRecvEntityEventID).ToList();
|
||||
if (eventsToSync.Count == 0) return;
|
||||
|
||||
Write(msg, eventsToSync.Cast<NetEntityEvent>().ToList(), client);
|
||||
}
|
||||
|
||||
protected override void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
|
||||
{
|
||||
var serverEvent = entityEvent as ServerEntityEvent;
|
||||
if (serverEvent == null) return;
|
||||
|
||||
serverEvent.Write(buffer, recipient);
|
||||
}
|
||||
|
||||
protected override void ReadEvent(NetIncomingMessage buffer, INetSerializable entity, float sendingTime, Client sender = null)
|
||||
{
|
||||
var clientEntity = entity as IClientSerializable;
|
||||
if (clientEntity == null) return;
|
||||
|
||||
clientEntity.ServerRead(buffer, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ namespace Barotrauma.Networking
|
||||
CHAT_MESSAGE,
|
||||
VOTE,
|
||||
ENTITY_POSITION,
|
||||
ITEM_STATE,
|
||||
ENTITY_STATE,
|
||||
|
||||
ENTITY_SPAWN
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user