Replaced fullsyncforced with reset

This commit is contained in:
2026-06-24 15:12:22 +02:00
parent 2f18464e71
commit 8255eb8b99
4 changed files with 428 additions and 337 deletions
+98 -53
View File
@@ -13,7 +13,6 @@ namespace Marro.PacManUdon
{
public enum NetworkEventType
{
FullSyncForced = 0,
FullSync = 1,
InputChange = 2,
StartGameButtonPressed = 3,
@@ -102,6 +101,9 @@ namespace Marro.PacManUdon
/// The total length of the header of an event, in bytes.
/// </summary>
private const ushort HeaderLength = 8;
private const ushort GuidSize = 16;
private const ushort ResetEventSize = HeaderTimestampIndex + GuidSize;
#endregion
#region Private attributes
@@ -155,6 +157,8 @@ namespace Marro.PacManUdon
/// </summary>
private int retriesWithoutSuccess;
private byte[] lastResetEventData;
/// <summary>
/// For receiver: True if there's a full sync in the queue and we are not synced, otherwise false.
/// For transmitter: True if there's a full sync in the queue which has not yet been transmitted, otherwise false.
@@ -302,22 +306,13 @@ namespace Marro.PacManUdon
/// </summary>
public void Initialize()
{
if (initialized)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Tried to call {nameof(Initialize)} when already initialized!");
return;
}
if (!BitConverter.IsLittleEndian)
{
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Fatal: NetworkManager only supports little endian! Network sync will not be possible.");
return;
}
if (root == null)
{
root = transform.parent.gameObject;
}
root = transform.parent.gameObject;
InitializeSubscribers();
@@ -341,6 +336,8 @@ namespace Marro.PacManUdon
networkEventSubscribers = new SyncedObject[eventTypeCount][];
networkEventSubscribersIndices = new int[eventTypeCount];
lastResetEventData = new byte[ResetEventSize];
}
public void Reset()
@@ -362,7 +359,6 @@ namespace Marro.PacManUdon
ClearBuffer();
Synced = IsOwner; // Owner is always synced
retriesWithoutSuccess = 0;
targetTicks = 0;
@@ -375,7 +371,12 @@ namespace Marro.PacManUdon
// Sync up
if (!IsOwner)
{
RequestEvent(NetworkEventType.FullSync);
SetSynced(false);
}
else
{
Synced = true; // Owner is always synced
SendReset();
}
//Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Initialized");
@@ -459,15 +460,13 @@ namespace Marro.PacManUdon
ClearBuffer();
}
Synced = false;
if (!IsOwner)
{
RequestEvent(NetworkEventType.FullSync);
SetSynced(false);
}
else
else if (clearBuffer)
{
SendEventSoon(NetworkEventType.FullSyncForced);
SendReset();
}
}
@@ -517,7 +516,7 @@ namespace Marro.PacManUdon
if (eventsToSendEarlyIndex >= eventsToSendEarly.Length)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) {nameof(eventsToSendEarly)} overflow!");
HandleError(false);
HandleError(true);
return;
}
@@ -528,14 +527,14 @@ namespace Marro.PacManUdon
if (eventsToSendLateIndex >= eventsToSendLate.Length)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) {nameof(eventsToSendLate)} overflow!");
HandleError(false);
HandleError(true);
return;
}
eventsToSendLate[eventsToSendLateIndex++] = eventType;
}
if (IsFullSync(eventType))
if (eventType == NetworkEventType.FullSync)
{
hasFullSyncReady = true;
}
@@ -582,15 +581,13 @@ namespace Marro.PacManUdon
InitializeEvent(eventType, timestamp, eventId, out byte[] data, out var index);
var effectiveEventType = eventType == NetworkEventType.FullSyncForced ? NetworkEventType.FullSync : eventType;
var subscibers = GetEventSubscribers(effectiveEventType);
var subscibers = GetEventSubscribers(eventType);
if (subscibers != null)
{
foreach (var obj in subscibers)
{
obj.CollectSyncedData(data, ref index, effectiveEventType);
obj.CollectSyncedData(data, ref index, eventType);
}
}
@@ -623,6 +620,19 @@ namespace Marro.PacManUdon
index = HeaderLength;
}
private void SendReset()
{
var data = new byte[ResetEventSize];
var guid = Guid.NewGuid().ToByteArray();
Array.Copy(guid, 0, data, HeaderTimestampIndex, GuidSize);
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Sent Reset event!");
QueueEventInBuffer(data);
RequestSerializationForEvents();
}
private void RequestSerializationForEvents()
{
RequestSerialization();
@@ -641,17 +651,12 @@ namespace Marro.PacManUdon
return;
}
if (IsFullSync(eventType) && hasFullSyncReady)
if (eventType == NetworkEventType.FullSync && hasFullSyncReady)
{
//Debug.Log($"Rejected event request because already have full sync ready");
return; // Don't send another full sync if we're already preparing to send one
}
if (eventType == NetworkEventType.FullSyncForced)
{
eventType = NetworkEventType.FullSync; // Remote is not allowed to request a forced full sync
}
SendEventSoon(eventType);
}
@@ -762,7 +767,7 @@ namespace Marro.PacManUdon
int eventSize = 0; // Store event size here so we can increment the index no matter how we increment the loop
while ((index += eventSize) < length)
{
if (length - index < HeaderLength)
if (length - index < HeaderLength) // Check package is at least as long as the minimum length possible. Reset package is also larger than HeaderLength.
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) {nameof(StoreIncomingData)}: Remaining data in networkedData is not long enough to form a complete event! remaining: {length - index}.");
HandleError(false);
@@ -770,6 +775,12 @@ namespace Marro.PacManUdon
}
eventSize = GetEventSizeFromHeader(networkedData, index);
bool isReset = eventSize == 0;
if (isReset)
{
eventSize = ResetEventSize;
}
if (length - index < eventSize)
{
@@ -787,11 +798,17 @@ namespace Marro.PacManUdon
var @event = GetArrayPart(networkedData, index, eventSize);
if (isReset)
{
TryApplyReset(@event);
return;
}
var timestamp = GetTimestampFromHeader(@event);
var eventId = GetEventIdFromHeader(@event);
var eventType = GetEventTypeFromHeader(@event);
if (eventType != NetworkEventType.FullSyncForced && (Synced || hasFullSyncReady))
if (Synced || hasFullSyncReady)
{
// Check if event id is sequential
if (eventId != GetNextEventId(lastEventId))
@@ -821,7 +838,7 @@ namespace Marro.PacManUdon
//Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)} Queued event with id {eventId}");
}
else if (IsFullSync(eventType)) // If we're not yet synced, we only care about full sync events.
else if (eventType == NetworkEventType.FullSync) // If we're not yet synced, we only care about full sync events.
{
QueueFullSyncForReplay(@event); // Immediately process full sync
}
@@ -849,6 +866,47 @@ namespace Marro.PacManUdon
//Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Queued full sync in buffer, should execute at {nextEventTime}.");
}
private void TryApplyReset(byte[] @event)
{
// Compare the guid to the one in the previous reset event
if (IsDuplicateResetEvent(@event))
{
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Rejected Reset event as it was a duplicate.");
return;
}
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Applied Reset event!");
lastResetEventData = @event;
ClearBuffer();
SetSynced(false);
}
private bool IsDuplicateResetEvent(byte[] @event)
{
for (int i = HeaderTimestampIndex; i < ResetEventSize; i++)
{
if (@event[i] != lastResetEventData[i])
{
return false;
}
}
return true;
}
private void SetSynced(bool synced)
{
Synced = synced;
if (!Synced)
{
Synced = false;
RequestEvent(NetworkEventType.FullSync);
lastEventTransmissionTime = SyncedTimeTicks;
}
}
private void ApplyReceivedEvents()
{
IsEventUpdate = true;
@@ -872,11 +930,11 @@ namespace Marro.PacManUdon
var timestamp = GetTimestampFromHeader(@event);
var eventType = GetEventTypeFromHeader(@event);
var isFullSync = IsFullSync(eventType);
if (!Synced || eventType == NetworkEventType.FullSyncForced)
if (!Synced)
{
SyncToTimestamp(timestamp);
hasFullSyncReady = false;
SetSynced(true);
}
else if (timestamp < SyncedTimeTicks)
{
@@ -886,11 +944,6 @@ namespace Marro.PacManUdon
return false;
}
if (eventType == NetworkEventType.FullSyncForced)
{
eventType = NetworkEventType.FullSync;
}
var index = (int)HeaderLength; // Skip header
var subscribers = GetEventSubscribers(eventType);
@@ -920,12 +973,6 @@ namespace Marro.PacManUdon
return false;
}
if (!Synced && isFullSync)
{
hasFullSyncReady = false;
Synced = true;
}
//Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Performed incoming event of type {eventType}! Total {index} bytes.");
retriesWithoutSuccess = 0; // We had success!
@@ -1064,9 +1111,6 @@ namespace Marro.PacManUdon
return currentEventId;
}
private static bool IsFullSync(NetworkEventType eventType)
=> eventType == NetworkEventType.FullSync || eventType == NetworkEventType.FullSyncForced;
private static ushort GetEventSizeFromHeader(byte[] @event, int eventIndex = 0)
=> BitConverter.ToUInt16(@event, eventIndex + HeaderEventSizeIndex);
@@ -1093,7 +1137,8 @@ namespace Marro.PacManUdon
if (newOwnerIsLocalPlayer)
{
SendEventSoon(NetworkEventType.FullSyncForced);
ClearBuffer();
SendReset();
}
}
#endregion
@@ -1244,7 +1289,7 @@ namespace Marro.PacManUdon
public void DoFullSync()
{
SendEventSoon(NetworkEventType.FullSyncForced);
SendEventSoon(NetworkEventType.FullSync);
}
public void Pause()