ServerEntityEventManager doesn't process received events until the character inputs of the client for the corresponding frame have been processed (fixes character movement lagging behind EntityEvents at the servers side)
+ split character networking logic into a separate file, characters drop items at the position of their collider instead of hands
This commit is contained in:
@@ -36,6 +36,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void CreateEvent(IClientSerializable entity, object[] extraData = null)
|
||||
{
|
||||
if (GameMain.Client == null || GameMain.Client.Character == null) return;
|
||||
|
||||
if (!(entity is Entity))
|
||||
{
|
||||
DebugConsole.ThrowError("Can't create an entity event for " + entity + "!");
|
||||
@@ -44,6 +46,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
ID++;
|
||||
var newEvent = new ClientEntityEvent(entity, ID);
|
||||
newEvent.CharacterStateID = GameMain.Client.Character.LastNetworkUpdateID;
|
||||
if (extraData != null) newEvent.SetData(extraData);
|
||||
|
||||
events.Add(newEvent);
|
||||
@@ -95,9 +98,56 @@ namespace Barotrauma.Networking
|
||||
Write(msg, eventsToSync);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the events from the message, ignoring ones we've already received
|
||||
/// </summary>
|
||||
public void Read(NetIncomingMessage msg, float sendingTime)
|
||||
{
|
||||
base.Read(msg, sendingTime, ref lastReceivedID);
|
||||
UInt32 firstEventID = msg.ReadUInt32();
|
||||
int eventCount = msg.ReadByte();
|
||||
|
||||
for (int i = 0; i < eventCount; i++)
|
||||
{
|
||||
UInt32 thisEventID = firstEventID + (UInt32)i;
|
||||
UInt16 entityID = msg.ReadUInt16();
|
||||
byte msgLength = msg.ReadByte();
|
||||
|
||||
IServerSerializable entity = Entity.FindEntityByID(entityID) as IServerSerializable;
|
||||
|
||||
//skip the event if we've already received it or if the entity isn't found
|
||||
if (thisEventID != lastReceivedID + 1 || entity == null)
|
||||
{
|
||||
if (thisEventID != lastReceivedID + 1)
|
||||
{
|
||||
DebugConsole.NewMessage("received msg " + thisEventID, Microsoft.Xna.Framework.Color.Red);
|
||||
}
|
||||
else if (entity == null)
|
||||
{
|
||||
DebugConsole.NewMessage("received msg " + thisEventID + ", entity " + entityID + " not found", Microsoft.Xna.Framework.Color.Red);
|
||||
}
|
||||
msg.Position += msgLength * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
long msgPosition = msg.Position;
|
||||
|
||||
DebugConsole.NewMessage("received msg " + thisEventID + " (" + entity.ToString() + ")", Microsoft.Xna.Framework.Color.Green);
|
||||
lastReceivedID++;
|
||||
try
|
||||
{
|
||||
ReadEvent(msg, entity, sendingTime);
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Failed to read event for entity \"" + entity.ToString() + "\"!", e);
|
||||
#endif
|
||||
msg.Position = msgPosition + msgLength * 8;
|
||||
}
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
|
||||
@@ -108,12 +158,9 @@ namespace Barotrauma.Networking
|
||||
clientEvent.Write(buffer);
|
||||
}
|
||||
|
||||
protected override void ReadEvent(NetIncomingMessage buffer, INetSerializable entity, float sendingTime, Client sender = null)
|
||||
protected void ReadEvent(NetIncomingMessage buffer, IServerSerializable entity, float sendingTime)
|
||||
{
|
||||
var serverEntity = entity as IServerSerializable;
|
||||
if (serverEntity == null) return;
|
||||
|
||||
serverEntity.ClientRead(ServerNetObject.ENTITY_STATE, buffer, sendingTime);
|
||||
entity.ClientRead(ServerNetObject.ENTITY_STATE, buffer, sendingTime);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
|
||||
@@ -83,6 +83,8 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
private IClientSerializable serializable;
|
||||
|
||||
public UInt16 CharacterStateID;
|
||||
|
||||
public ClientEntityEvent(IClientSerializable entity, UInt32 id)
|
||||
: base(entity, id)
|
||||
{
|
||||
@@ -91,6 +93,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void Write(NetBuffer msg)
|
||||
{
|
||||
msg.Write(CharacterStateID);
|
||||
serializable.ClientWrite(msg, Data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Barotrauma.Networking
|
||||
WriteEvent(tempBuffer, e, recipient);
|
||||
|
||||
Debug.Assert(
|
||||
tempBuffer.LengthBytes < 256,
|
||||
tempBuffer.LengthBytes < 128,
|
||||
"Maximum EntityEvent size exceeded when serializing \""+e.Entity+"\"!");
|
||||
|
||||
#if DEBUG
|
||||
@@ -50,67 +50,10 @@ namespace Barotrauma.Networking
|
||||
msg.WritePadBits();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the events from the message, ignoring ones we've already received
|
||||
/// </summary>
|
||||
protected void Read(NetIncomingMessage msg, float sendingTime, ref UInt32 lastReceivedID, Client sender = null)
|
||||
{
|
||||
UInt32 firstEventID = msg.ReadUInt32();
|
||||
int 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 != lastReceivedID + 1 || entity == null)
|
||||
{
|
||||
if (thisEventID != lastReceivedID + 1)
|
||||
{
|
||||
DebugConsole.NewMessage("received msg "+thisEventID, Microsoft.Xna.Framework.Color.Red);
|
||||
}
|
||||
else if (entity == null)
|
||||
{
|
||||
DebugConsole.NewMessage("received msg " + thisEventID+", entity "+entityID+" not found", Microsoft.Xna.Framework.Color.Red);
|
||||
}
|
||||
msg.Position += msgLength * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
long msgPosition = msg.Position;
|
||||
|
||||
DebugConsole.NewMessage("received msg "+thisEventID+ " ("+entity.ToString()+")", Microsoft.Xna.Framework.Color.Green);
|
||||
lastReceivedID++;
|
||||
try
|
||||
{
|
||||
ReadEvent(msg, entity, sendingTime, sender);
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Failed to read event for entity \""+entity.ToString()+"\"!", e);
|
||||
#endif
|
||||
msg.Position = msgPosition + msgLength * 8;
|
||||
}
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,33 @@ namespace Barotrauma.Networking
|
||||
get { return events; }
|
||||
}
|
||||
|
||||
private class BufferedEvent
|
||||
{
|
||||
public readonly Client Sender;
|
||||
|
||||
public readonly UInt16 CharacterStateID;
|
||||
public readonly NetBuffer Data;
|
||||
|
||||
public readonly Character Character;
|
||||
|
||||
public readonly IClientSerializable TargetEntity;
|
||||
|
||||
public bool IsProcessed;
|
||||
|
||||
public BufferedEvent(Client sender, Character senderCharacter, UInt16 characterStateID, IClientSerializable targetEntity, NetBuffer data)
|
||||
{
|
||||
this.Sender = sender;
|
||||
this.Character = senderCharacter;
|
||||
this.CharacterStateID = characterStateID;
|
||||
|
||||
this.TargetEntity = targetEntity;
|
||||
|
||||
this.Data = data;
|
||||
}
|
||||
}
|
||||
|
||||
private List<BufferedEvent> bufferedEvents;
|
||||
|
||||
private UInt32 ID;
|
||||
|
||||
private GameServer server;
|
||||
@@ -25,6 +52,8 @@ namespace Barotrauma.Networking
|
||||
events = new List<ServerEntityEvent>();
|
||||
|
||||
this.server = server;
|
||||
|
||||
bufferedEvents = new List<BufferedEvent>();
|
||||
}
|
||||
|
||||
public void CreateEvent(IServerSerializable entity, object[] extraData = null)
|
||||
@@ -50,6 +79,51 @@ namespace Barotrauma.Networking
|
||||
events.Add(newEvent);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
foreach (BufferedEvent bufferedEvent in bufferedEvents)
|
||||
{
|
||||
if (bufferedEvent.Character == null)
|
||||
{
|
||||
bufferedEvent.IsProcessed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(bufferedEvent.CharacterStateID, bufferedEvent.Character.LastProcessedID)) continue;
|
||||
|
||||
try
|
||||
{
|
||||
ReadEvent(bufferedEvent.Data, bufferedEvent.TargetEntity, bufferedEvent.Sender);
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Failed to read event for entity \"" + bufferedEvent.TargetEntity.ToString() + "\"!", e);
|
||||
#endif
|
||||
}
|
||||
|
||||
bufferedEvent.IsProcessed = true;
|
||||
}
|
||||
|
||||
bufferedEvents.RemoveAll(b => b.IsProcessed);
|
||||
}
|
||||
|
||||
private void BufferEvent(BufferedEvent bufferedEvent)
|
||||
{
|
||||
if (bufferedEvents.Count > 512)
|
||||
{
|
||||
//should normally never happen
|
||||
|
||||
//a client could potentially spam events with a much higher character state ID
|
||||
//than the state of their character and/or stop sending character inputs,
|
||||
//so we'll drop some events to make sure no-one blows up our buffer
|
||||
bufferedEvents.RemoveRange(0, 256);
|
||||
}
|
||||
|
||||
bufferedEvents.Add(bufferedEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes all the events that the client hasn't received yet into the outgoing message
|
||||
/// </summary>
|
||||
@@ -99,6 +173,49 @@ namespace Barotrauma.Networking
|
||||
Write(msg, eventsToSync, client);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the events from the message, ignoring ones we've already received
|
||||
/// </summary>
|
||||
public void Read(NetIncomingMessage msg, Client sender = null)
|
||||
{
|
||||
UInt32 firstEventID = msg.ReadUInt32();
|
||||
int eventCount = msg.ReadByte();
|
||||
|
||||
for (int i = 0; i < eventCount; i++)
|
||||
{
|
||||
UInt32 thisEventID = firstEventID + (UInt32)i;
|
||||
UInt16 entityID = msg.ReadUInt16();
|
||||
byte msgLength = msg.ReadByte();
|
||||
|
||||
IClientSerializable entity = Entity.FindEntityByID(entityID) as IClientSerializable;
|
||||
|
||||
//skip the event if we've already received it or if the entity isn't found
|
||||
if (thisEventID != sender.lastSentEntityEventID + 1 || entity == null)
|
||||
{
|
||||
if (thisEventID != sender.lastSentEntityEventID + 1)
|
||||
{
|
||||
DebugConsole.NewMessage("received msg " + thisEventID, Microsoft.Xna.Framework.Color.Red);
|
||||
}
|
||||
else if (entity == null)
|
||||
{
|
||||
DebugConsole.NewMessage("received msg " + thisEventID + ", entity " + entityID + " not found", Microsoft.Xna.Framework.Color.Red);
|
||||
}
|
||||
msg.Position += msgLength * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt16 characterStateID = msg.ReadUInt16();
|
||||
|
||||
NetBuffer buffer = new NetBuffer();
|
||||
buffer.Write(msg.ReadBytes(msgLength-2));
|
||||
BufferEvent(new BufferedEvent(sender, sender.Character, characterStateID, entity, buffer));
|
||||
|
||||
sender.lastSentEntityEventID++;
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
|
||||
{
|
||||
var serverEvent = entityEvent as ServerEntityEvent;
|
||||
@@ -107,24 +224,21 @@ namespace Barotrauma.Networking
|
||||
serverEvent.Write(buffer, recipient);
|
||||
}
|
||||
|
||||
protected override void ReadEvent(NetIncomingMessage buffer, INetSerializable entity, float sendingTime, Client sender = null)
|
||||
protected void ReadEvent(NetBuffer buffer, INetSerializable entity, Client sender = null)
|
||||
{
|
||||
var clientEntity = entity as IClientSerializable;
|
||||
if (clientEntity == null) return;
|
||||
|
||||
|
||||
clientEntity.ServerRead(ClientNetObject.ENTITY_STATE, buffer, sender);
|
||||
}
|
||||
|
||||
public void Read(NetIncomingMessage msg, Client client)
|
||||
{
|
||||
base.Read(msg, 0.0f, ref client.lastSentEntityEventID, client);
|
||||
}
|
||||
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ID = 0;
|
||||
events.Clear();
|
||||
|
||||
bufferedEvents.Clear();
|
||||
|
||||
server.ConnectedClients.ForEach(c => c.entityEventLastSent.Clear());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user