2 using System.Collections.Generic;
3 using Microsoft.Xna.Framework;
9 private List<ClientEntityEvent> events;
21 get {
return lastReceivedID; }
24 private UInt16 lastReceivedID;
28 get {
return firstNewID.HasValue; }
39 events =
new List<ClientEntityEvent>();
54 eventId: (UInt16)(ID + 1),
56 if (extraData !=
null) { newEvent.SetData(extraData); }
58 for (
int i = events.Count - 1; i >= 0; i--)
62 if (!events[i].Sent && events[i].IsDuplicate(newEvent))
return;
72 if (events.Count == 0 || serverConnection ==
null)
return;
74 List<NetEntityEvent> eventsToSync =
new List<NetEntityEvent>();
77 int startIndex = events.Count;
78 while (startIndex > 0 &&
85 events.RemoveRange(0, startIndex);
87 for (
int i = 0; i < events.Count; i++)
92 if (lastSent > Lidgren.Network.NetTime.Now - 0.2)
97 eventsToSync.AddRange(events.GetRange(i, events.Count - i));
100 if (eventsToSync.Count == 0) {
return; }
108 Write(msg, eventsToSync, out _);
111 private UInt16? firstNewID;
113 private readonly List<IServerSerializable> tempEntityList =
new List<IServerSerializable>();
121 UInt16 unreceivedEntityEventCount = msg.
ReadUInt16();
124 if (GameSettings.CurrentConfig.VerboseLogging)
126 DebugConsole.NewMessage(
127 "received midround syncing msg, unreceived: " + unreceivedEntityEventCount +
128 ", first new ID: " + firstNewID, Microsoft.Xna.Framework.Color.Yellow);
134 if (firstNewID !=
null)
136 if (GameSettings.CurrentConfig.VerboseLogging)
138 DebugConsole.NewMessage(
"midround syncing complete, switching to ID " + (UInt16) (firstNewID - 1),
139 Microsoft.Xna.Framework.Color.Yellow);
141 lastReceivedID = (UInt16)(firstNewID - 1);
146 tempEntityList.Clear();
152 for (
int i = 0; i < eventCount; i++)
157 string errorMsg = $
"Error while reading a message from the server. Entity event data exceeds the size of the buffer (current position: {msg.BitPosition}, length: {msg.LengthBits}).";
158 errorMsg +=
"\nPrevious entities:";
159 for (
int j = tempEntityList.Count - 1; j >= 0; j--)
161 errorMsg +=
"\n" + (tempEntityList[j] ==
null ?
"NULL" : tempEntityList[j].ToString());
163 DebugConsole.ThrowError(errorMsg);
167 UInt16 thisEventID = (UInt16)(firstEventID + (UInt16)i);
172 if (GameSettings.CurrentConfig.VerboseLogging)
174 DebugConsole.NewMessage(
"received msg " + thisEventID +
" (null entity)",
175 Microsoft.Xna.Framework.Color.Orange);
177 tempEntityList.Add(
null);
178 if (thisEventID == (UInt16)(lastReceivedID + 1)) { lastReceivedID++; }
185 tempEntityList.Add(entity);
188 if (thisEventID != (UInt16)(lastReceivedID + 1) || entity ==
null)
190 if (thisEventID != (UInt16) (lastReceivedID + 1))
192 if (GameSettings.CurrentConfig.VerboseLogging)
194 DebugConsole.NewMessage(
195 "Received msg " + thisEventID +
" (waiting for " + (lastReceivedID + 1) +
")",
196 NetIdUtils.IdMoreRecent(thisEventID, (UInt16)(lastReceivedID + 1))
198 : Microsoft.Xna.Framework.Color.Yellow);
201 else if (entity ==
null)
203 DebugConsole.NewMessage(
204 "Received msg " + thisEventID +
", entity " + entityID +
" not found",
215 if (GameSettings.CurrentConfig.VerboseLogging)
217 DebugConsole.NewMessage(
"received msg " + thisEventID +
" (" + entity.ToString() +
")",
218 Microsoft.Xna.Framework.Color.Green);
224 if (msg.
BitPosition != msgPosition + msgLength * 8)
226 var prevEntity = tempEntityList.Count >= 2 ? tempEntityList[tempEntityList.Count - 2] :
null;
227 ushort prevId = prevEntity is
Entity p ? p.
ID : (ushort)0;
228 string errorMsg = $
"Message byte position incorrect after reading an event for the entity \"{entity}\" (ID {(entity is Entity e ? e.ID : 0)}). "
229 +$
"The previous entity was \"{prevEntity}\" (ID {prevId}) "
230 +$
"Read {msg.BitPosition - msgPosition} bits, expected message length was {msgLength * 8} bits.";
232 GameAnalyticsManager.AddErrorEventOnce(
"ClientEntityEventManager.Read:BitPosMismatch", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
234 throw new Exception(errorMsg);
244 if (clientEvent ==
null)
return;
246 clientEvent.
Write(buffer);
247 clientEvent.Sent =
true;
273 if (thisClient !=
null)
UInt16 LastNetworkUpdateID
const ushort NullEntityID
readonly ushort ID
Unique, but non-persistent identifier. Stays the same if the entities are created in the exactly same...
static Entity FindEntityByID(ushort ID)
Find an entity based on the ID
void Write(IWriteMessage msg)
void ClearSelf()
Clears events generated by the current client, used when resynchronizing with the server after a time...
bool Read(ServerNetSegment type, IReadMessage msg, float sendingTime)
Read the events from the message, ignoring ones we've already received. Returns false if reading the ...
ClientEntityEventManager(GameClient client)
void Write(in SegmentTableWriter< ClientNetSegment > segmentTable, IWriteMessage msg, NetworkConnection serverConnection)
void ReadEvent(IReadMessage buffer, IServerSerializable entity, float sendingTime)
void CreateEvent(IClientSerializable entity, NetEntityEvent.IData extraData=null, bool requireControlledCharacter=true)
override void WriteEvent(IWriteMessage buffer, NetEntityEvent entityEvent, Client recipient=null)
Dictionary< UInt16, float > eventLastSent
UInt16 LastSentEntityEventID
void ReportError(ClientNetError error, UInt16 expectedId=0, UInt16 eventId=0, UInt16 entityId=0)
static bool ValidateEntity(INetSerializable entity)
Interface for entities that the clients can send events to the server
UInt32 ReadVariableUInt32()
Interface for entities that the server can send events to the clients
void ClientEventRead(IReadMessage msg, float sendingTime)