Improved initial sync

This commit is contained in:
2026-06-24 11:38:43 +02:00
parent 3be8d2f6a6
commit ad605bcab3
5 changed files with 1309 additions and 1238 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+54 -38
View File
@@ -53,15 +53,19 @@ namespace Marro.PacManUdon
/// <summary> /// <summary>
/// The delay in ticks at which the receiving side replays events. /// The delay in ticks at which the receiving side replays events.
/// </summary> /// </summary>
[SerializeField] private int delay = 50; [SerializeField] private int delay = 1;
/// <summary> /// <summary>
/// The maximum amount of times a message is sent. /// The maximum amount of times a message is sent.
/// </summary> /// </summary>
[SerializeField] private int maxEventSendTries = 3; [SerializeField] private int maxEventSendTries = 3;
/// <summary> /// <summary>
/// How long to wait since last message to send next ping. /// How long to wait since last message to send next message.
/// </summary> /// </summary>
[SerializeField] private int pingDelay = 15; [SerializeField] private int sendingPingDelay = 15;
/// <summary>
/// How long to wait since last attempt to request sync.
/// </summary>
[SerializeField] private int syncingPingDelay = 300;
/// <summary> /// <summary>
/// The time delta at which updates occur. /// The time delta at which updates occur.
/// </summary> /// </summary>
@@ -200,7 +204,7 @@ namespace Marro.PacManUdon
/// </summary> /// </summary>
private int eventTransmissionHistoryIndex; private int eventTransmissionHistoryIndex;
/// <summary> /// <summary>
/// Time of last event transmission, in ticks. /// Time of last event transmission sent, requested or received, in ticks.
/// </summary> /// </summary>
private int lastEventTransmissionTime; private int lastEventTransmissionTime;
@@ -210,7 +214,6 @@ namespace Marro.PacManUdon
/// </summary> /// </summary>
private byte lastEventId; private byte lastEventId;
/// <summary> /// <summary>
/// Data which is currently available on the network. /// Data which is currently available on the network.
/// </summary> /// </summary>
@@ -295,7 +298,7 @@ namespace Marro.PacManUdon
#region General #region General
/// <summary> /// <summary>
/// Initializes the <see cref="NetworkManager"/>. Call <see cref="Reset"/> afterwards to activate networking. /// Initializes the <see cref="NetworkManager"/>.
/// </summary> /// </summary>
public void Initialize() public void Initialize()
{ {
@@ -361,7 +364,6 @@ namespace Marro.PacManUdon
Synced = IsOwner; // Owner is always synced Synced = IsOwner; // Owner is always synced
retriesWithoutSuccess = 0; retriesWithoutSuccess = 0;
hasFullSyncReady = false;
targetTicks = 0; targetTicks = 0;
startTime = Time.fixedTime; startTime = Time.fixedTime;
@@ -371,11 +373,7 @@ namespace Marro.PacManUdon
Ready = true; Ready = true;
// Sync up // Sync up
if (IsOwner) if (!IsOwner)
{
SendEventSoon(NetworkEventType.FullSyncForced);
}
else
{ {
RequestEvent(NetworkEventType.FullSync); RequestEvent(NetworkEventType.FullSync);
} }
@@ -409,15 +407,19 @@ namespace Marro.PacManUdon
{ {
if (Ready) if (Ready)
{ {
if (IsOwner) if (isOwner)
{ {
ProcessEventsToSend(); // Prepare events from last cycle ProcessEventsToSend(); // Prepare events from last cycle
ProgressPingTime(); // See if we need to send a ping ProgressSendingPingTime(); // See if we need to send a ping
} }
if (!isOwner) else if (Synced || hasFullSyncReady)
{ {
ApplyReceivedEvents(); // See if there's events after last update that need to be replayed ApplyReceivedEvents(); // See if there's events after last update that need to be replayed
} }
else
{
ProgressSyncingPingTime(); // See if we should request syncing
}
} }
ProgressSyncedTime(); ProgressSyncedTime();
@@ -532,6 +534,11 @@ namespace Marro.PacManUdon
eventsToSendLate[eventsToSendLateIndex++] = eventType; eventsToSendLate[eventsToSendLateIndex++] = eventType;
} }
if (IsFullSync(eventType))
{
hasFullSyncReady = true;
}
} }
private void ProcessEventsToSend() private void ProcessEventsToSend()
@@ -591,11 +598,6 @@ namespace Marro.PacManUdon
var eventSizeBytes = BitConverter.GetBytes((ushort)index); var eventSizeBytes = BitConverter.GetBytes((ushort)index);
Array.Copy(eventSizeBytes, 0, data, HeaderEventSizeIndex, eventSizeBytes.Length); Array.Copy(eventSizeBytes, 0, data, HeaderEventSizeIndex, eventSizeBytes.Length);
if (IsFullSync(eventType))
{
hasFullSyncReady = true;
}
data = GetArrayPart(data, 0, index); data = GetArrayPart(data, 0, index);
QueueEventInBuffer(data); QueueEventInBuffer(data);
@@ -641,27 +643,35 @@ namespace Marro.PacManUdon
if (IsFullSync(eventType) && hasFullSyncReady) if (IsFullSync(eventType) && 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 return; // Don't send another full sync if we're already preparing to send one
} }
if (eventType == NetworkEventType.FullSyncForced) if (eventType == NetworkEventType.FullSyncForced)
{ {
SendEventSoon(NetworkEventType.FullSync); // Remote is not allowed to request a forced full sync eventType = NetworkEventType.FullSync; // Remote is not allowed to request a forced full sync
return;
} }
SendEventSoon(eventType); SendEventSoon(eventType);
} }
private void ProgressPingTime() private void ProgressSendingPingTime()
{ {
if (eventsQueueIndex > 0 && !serializationRequested if (eventsQueueIndex > 0 && !serializationRequested
&& targetTicks - lastEventTransmissionTime >= pingDelay) && targetTicks - lastEventTransmissionTime >= sendingPingDelay)
{ {
RequestSerializationForEvents(); RequestSerializationForEvents();
} }
} }
private void ProgressSyncingPingTime()
{
if (targetTicks - lastEventTransmissionTime >= syncingPingDelay)
{
RequestEvent(NetworkEventType.FullSync);
}
}
public override void OnPreSerialization() public override void OnPreSerialization()
{ {
if (!Ready || !IsOwner || !serializationRequested || eventsQueue == null || eventsQueueIndex == 0) if (!Ready || !IsOwner || !serializationRequested || eventsQueue == null || eventsQueueIndex == 0)
@@ -688,6 +698,9 @@ namespace Marro.PacManUdon
// Version of OnPostSerialization which does not require instantiating SerializationResult, so that it can be called for debugging purposes. // Version of OnPostSerialization which does not require instantiating SerializationResult, so that it can be called for debugging purposes.
public void OnPostSerializationInternal(bool success, int byteCount) public void OnPostSerializationInternal(bool success, int byteCount)
{ {
// If there was a full sync in the queue, it should now have been transmitted at least once
hasFullSyncReady = false;
if (!Ready || !IsOwner || networkedData.Length == 0) if (!Ready || !IsOwner || networkedData.Length == 0)
{ {
return; return;
@@ -708,9 +721,6 @@ namespace Marro.PacManUdon
networkedData = new byte[0]; networkedData = new byte[0];
// If there was a full sync in the queue, it has now been transmitted at least once
hasFullSyncReady = false;
lastEventTransmissionTime = targetTicks; lastEventTransmissionTime = targetTicks;
} }
#endregion #endregion
@@ -730,6 +740,7 @@ namespace Marro.PacManUdon
} }
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, "RequestEventReceived", eventType); SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, "RequestEventReceived", eventType);
lastEventTransmissionTime = SyncedTimeTicks;
if (tester != null) if (tester != null)
{ {
@@ -798,25 +809,29 @@ namespace Marro.PacManUdon
continue; continue;
} }
QueueEventInBuffer(@event); if (!QueueEventInBuffer(@event))
{
return;
}
if (eventsQueueIndex == 1) // If this is the next upcoming event, update the next event time
{
UpdateNextEventTime();
}
//Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)} Queued event with id {eventId}"); //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.
{
QueueFullSyncForReplay(@event); // Immediately process full sync
}
else else
{ {
// If we're not yet synced, we only care about full sync events. return;
if (IsFullSync(eventType))
{
QueueFullSyncForReplay(@event); // Immediately process full sync
}
} }
lastEventId = eventId; lastEventId = eventId;
} lastEventTransmissionTime = SyncedTimeTicks;
if (Synced)
{
UpdateNextEventTime();
} }
} }
@@ -1211,6 +1226,7 @@ namespace Marro.PacManUdon
[SerializeField] private Animator DebugImageToIndicateReady; [SerializeField] private Animator DebugImageToIndicateReady;
private NetworkManagerTester tester; private NetworkManagerTester tester;
public void SetNetworkManagerTester(NetworkManagerTester tester) public void SetNetworkManagerTester(NetworkManagerTester tester)
{ {
this.tester = tester; this.tester = tester;
@@ -12,6 +12,7 @@ public class NetworkManagerSyncTester : UdonSharpBehaviour
[SerializeField] GridMover[] gridMovers1; [SerializeField] GridMover[] gridMovers1;
[SerializeField] NetworkManager networkManager2; [SerializeField] NetworkManager networkManager2;
[SerializeField] GridMover[] gridMovers2; [SerializeField] GridMover[] gridMovers2;
[SerializeField] Animator debugImageToIndicateSynced; [SerializeField] Animator debugImageToIndicateSynced;
private int[] captureTimes = new int[1000]; private int[] captureTimes = new int[1000];
+3 -3
View File
@@ -7,7 +7,7 @@ using UnityEngine;
public class NetworkManagerTester : UdonSharpBehaviour public class NetworkManagerTester : UdonSharpBehaviour
{ {
[SerializeField] private NetworkManager[] networkManagers; [SerializeField] private NetworkManager[] networkManagers;
[SerializeField] private float interval = 0.1f; [SerializeField] private float interval = 0.01f;
[SerializeField] private int ownerIndex = 0; [SerializeField] private int ownerIndex = 0;
private float countdown = 0; private float countdown = 0;
@@ -62,7 +62,7 @@ public class NetworkManagerTester : UdonSharpBehaviour
{ {
networkManager.OnPreSerialization(); networkManager.OnPreSerialization();
var data = networkManager.NetworkedData; var data = networkManager.NetworkedData;
networkManager.OnPostSerializationInternal(true, data.Length) ; networkManager.OnPostSerializationInternal(true, data.Length);
return data; return data;
} }
@@ -86,7 +86,7 @@ public class NetworkManagerTester : UdonSharpBehaviour
{ {
foreach (var target in networkManagers) foreach (var target in networkManagers)
{ {
if (!target.IsOwner || !target.SerializationRequested) if (!target.IsOwner)
{ {
continue; continue;
} }