Kinda working refactor

This commit is contained in:
2026-01-05 20:10:13 +01:00
parent 2636e65e4d
commit 630dc5a176
3 changed files with 356 additions and 285 deletions

View File

@@ -424,9 +424,9 @@ namespace Marro.PacManUdon
public override void AppendSyncedData(byte[][] data, ref int offset, NetworkEventType eventType) public override void AppendSyncedData(byte[][] data, ref int offset, NetworkEventType eventType)
{ {
data[offset++] = new byte[] { Int32ToByte((int)gameState) }; data[offset++] = new byte[] { NetworkManager.Int32ToByte((int)gameState) };
data[offset++] = BitConverter.GetBytes(currentlyInTimeSequence); data[offset++] = BitConverter.GetBytes(currentlyInTimeSequence);
data[offset++] = new byte[] { Int32ToByte((int)currentTimeSequence) }; data[offset++] = new byte[] { NetworkManager.Int32ToByte((int)currentTimeSequence) };
data[offset++] = BitConverter.GetBytes(timeSequenceProgress); data[offset++] = BitConverter.GetBytes(timeSequenceProgress);
} }
@@ -496,9 +496,5 @@ namespace Marro.PacManUdon
} }
get => level; get => level;
} }
public static byte Int32ToByte(int value) =>
(byte)value;
//byte.Parse(value.ToString()); // This is the only way I could find to cast an int to byte in Udon, a regular cast crashes in runtime...
} }
} }

View File

@@ -43,7 +43,7 @@ MonoBehaviour:
Data: Data:
- Name: - Name:
Entry: 12 Entry: 12
Data: 17 Data: 18
- Name: - Name:
Entry: 7 Entry: 7
Data: Data:
@@ -539,6 +539,114 @@ MonoBehaviour:
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 7 Entry: 7
Data: 29|System.RuntimeType, mscorlib Data: 29|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Byte[][], mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 7
Data: 30|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Object[], mscorlib
- Name:
Entry: 8
Data:
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 31|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: bufferIndex
- Name: $v
Entry: 7
Data: 32|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: bufferIndex
- Name: <UserType>k__BackingField
Entry: 9
Data: 26
- Name: <SystemType>k__BackingField
Entry: 9
Data: 26
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 33|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: networkedData
- Name: $v
Entry: 7
Data: 34|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: networkedData
- Name: <UserType>k__BackingField
Entry: 7
Data: 35|System.RuntimeType, mscorlib
- Name: - Name:
Entry: 1 Entry: 1
Data: System.Byte[], mscorlib Data: System.Byte[], mscorlib
@@ -547,103 +655,7 @@ MonoBehaviour:
Data: Data:
- Name: <SystemType>k__BackingField - Name: <SystemType>k__BackingField
Entry: 9 Entry: 9
Data: 29 Data: 35
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 30|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: bufferIndex
- Name: $v
Entry: 7
Data: 31|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: bufferIndex
- Name: <UserType>k__BackingField
Entry: 9
Data: 26
- Name: <SystemType>k__BackingField
Entry: 9
Data: 26
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 32|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: networkedData
- Name: $v
Entry: 7
Data: 33|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: networkedData
- Name: <UserType>k__BackingField
Entry: 9
Data: 29
- Name: <SystemType>k__BackingField
Entry: 9
Data: 29
- Name: <SyncMode>k__BackingField - Name: <SyncMode>k__BackingField
Entry: 7 Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
@@ -658,13 +670,13 @@ MonoBehaviour:
Data: false Data: false
- Name: _fieldAttributes - Name: _fieldAttributes
Entry: 7 Entry: 7
Data: 34|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib Data: 36|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name: - Name:
Entry: 12 Entry: 12
Data: 1 Data: 1
- Name: - Name:
Entry: 7 Entry: 7
Data: 35|UdonSharp.UdonSyncedAttribute, UdonSharp.Runtime Data: 37|UdonSharp.UdonSyncedAttribute, UdonSharp.Runtime
- Name: - Name:
Entry: 8 Entry: 8
Data: Data:
@@ -686,66 +698,18 @@ MonoBehaviour:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: <Ready>k__BackingField Data: <Ready>k__BackingField
- Name: $v
Entry: 7
Data: 36|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: <Ready>k__BackingField
- Name: <UserType>k__BackingField
Entry: 9
Data: 8
- Name: <SystemType>k__BackingField
Entry: 9
Data: 8
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 37|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: <SyncedTime>k__BackingField
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 38|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 38|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: <SyncedTime>k__BackingField Data: <Ready>k__BackingField
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 9 Entry: 9
Data: 13 Data: 8
- Name: <SystemType>k__BackingField - Name: <SystemType>k__BackingField
Entry: 9 Entry: 9
Data: 13 Data: 8
- Name: <SyncMode>k__BackingField - Name: <SyncMode>k__BackingField
Entry: 7 Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
@@ -781,13 +745,13 @@ MonoBehaviour:
Data: Data:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: <Dt>k__BackingField Data: <SyncedTime>k__BackingField
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 40|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 40|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: <Dt>k__BackingField Data: <SyncedTime>k__BackingField
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 9 Entry: 9
Data: 13 Data: 13
@@ -829,19 +793,19 @@ MonoBehaviour:
Data: Data:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: <IsEventUpdate>k__BackingField Data: <Dt>k__BackingField
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 42|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 42|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: <IsEventUpdate>k__BackingField Data: <Dt>k__BackingField
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 9 Entry: 9
Data: 8 Data: 13
- Name: <SystemType>k__BackingField - Name: <SystemType>k__BackingField
Entry: 9 Entry: 9
Data: 8 Data: 13
- Name: <SyncMode>k__BackingField - Name: <SyncMode>k__BackingField
Entry: 7 Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
@@ -877,16 +841,112 @@ MonoBehaviour:
Data: Data:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: DebugImageToIndicateOwner Data: <IsEventUpdate>k__BackingField
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 44|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 44|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: <IsEventUpdate>k__BackingField
- Name: <UserType>k__BackingField
Entry: 9
Data: 8
- Name: <SystemType>k__BackingField
Entry: 9
Data: 8
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 45|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: indexAtLastSerialization
- Name: $v
Entry: 7
Data: 46|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: indexAtLastSerialization
- Name: <UserType>k__BackingField
Entry: 9
Data: 26
- Name: <SystemType>k__BackingField
Entry: 9
Data: 26
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 47|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: DebugImageToIndicateOwner
- Name: $v
Entry: 7
Data: 48|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: DebugImageToIndicateOwner Data: DebugImageToIndicateOwner
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 7 Entry: 7
Data: 45|System.RuntimeType, mscorlib Data: 49|System.RuntimeType, mscorlib
- Name: - Name:
Entry: 1 Entry: 1
Data: UnityEngine.Animator, UnityEngine.AnimationModule Data: UnityEngine.Animator, UnityEngine.AnimationModule
@@ -895,7 +955,7 @@ MonoBehaviour:
Data: Data:
- Name: <SystemType>k__BackingField - Name: <SystemType>k__BackingField
Entry: 9 Entry: 9
Data: 45 Data: 49
- Name: <SyncMode>k__BackingField - Name: <SyncMode>k__BackingField
Entry: 7 Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
@@ -910,13 +970,13 @@ MonoBehaviour:
Data: true Data: true
- Name: _fieldAttributes - Name: _fieldAttributes
Entry: 7 Entry: 7
Data: 46|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib Data: 50|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name: - Name:
Entry: 12 Entry: 12
Data: 1 Data: 1
- Name: - Name:
Entry: 7 Entry: 7
Data: 47|UnityEngine.SerializeField, UnityEngine.CoreModule Data: 51|UnityEngine.SerializeField, UnityEngine.CoreModule
- Name: - Name:
Entry: 8 Entry: 8
Data: Data:

View File

@@ -2,6 +2,8 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using System; using System;
using System.Drawing; using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text; using System.Text;
using TMPro; using TMPro;
using UdonSharp; using UdonSharp;
@@ -44,11 +46,7 @@ namespace Marro.PacManUdon
/// <summary> /// <summary>
/// The maximum size of the buffer in bytes. /// The maximum size of the buffer in bytes.
/// </summary> /// </summary>
private const int BufferMaxSizeBytes = 10000; private const int BufferMaxTotalEvents = 255;
/// <summary>
/// How many bytes to increase the buffer size by if the current one is not enough.
/// </summary>
private const int BufferIncrementSizeBytes = 1000;
/// <summary> /// <summary>
/// The index in an event where the event size is stored. /// The index in an event where the event size is stored.
@@ -71,10 +69,6 @@ namespace Marro.PacManUdon
/// </summary> /// </summary>
private const ushort HeaderLength = 8; private const ushort HeaderLength = 8;
/// <summary> /// <summary>
/// The length of the event size part of the header, in bytes.
/// </summary>
private const ushort HeaderEventSizeBytes = 2;
/// <summary>
/// The amount of parts of which the header consists. /// The amount of parts of which the header consists.
/// </summary> /// </summary>
private const ushort HeaderPartsCount = 4; private const ushort HeaderPartsCount = 4;
@@ -86,7 +80,7 @@ namespace Marro.PacManUdon
/// <summary> /// <summary>
/// The zero value of a timestamp. Anything below this value is negative. /// The zero value of a timestamp. Anything below this value is negative.
/// </summary> /// </summary>
private const uint TimestampZeroValue = 1000; private const uint TimestampZeroValue = 10000;
/// <summary> /// <summary>
/// The delay at which the receiving side replays events. /// The delay at which the receiving side replays events.
/// </summary> /// </summary>
@@ -140,7 +134,7 @@ namespace Marro.PacManUdon
/// <summary> /// <summary>
/// Main buffer of data to be transmitted or processed /// Main buffer of data to be transmitted or processed
/// </summary> /// </summary>
private byte[] buffer; private byte[][] buffer;
/// <summary> /// <summary>
/// Index of <see cref="buffer"/>. /// Index of <see cref="buffer"/>.
/// </summary> /// </summary>
@@ -200,7 +194,7 @@ namespace Marro.PacManUdon
SetOwner(Networking.IsOwner(gameObject)); SetOwner(Networking.IsOwner(gameObject));
buffer = new byte[BufferIncrementSizeBytes]; buffer = new byte[BufferMaxTotalEvents][];
bufferIndex = 0; bufferIndex = 0;
isSynced = isOwner; // Owner is always synced isSynced = isOwner; // Owner is always synced
retriesWithoutSuccess = 0; retriesWithoutSuccess = 0;
@@ -300,31 +294,31 @@ namespace Marro.PacManUdon
var eventId = GetNextEventId(lastEventId); var eventId = GetNextEventId(lastEventId);
InitializeEvent(eventType, timestamp, eventId, BufferMaxSizeBytes, out byte[][] data, out var index); InitializeEvent(eventType, timestamp, eventId, BufferMaxTotalEvents, out byte[][] data, out var index);
foreach (var obj in syncedObjects) foreach (var obj in syncedObjects)
{ {
obj.AppendSyncedData(data, ref index, eventType); obj.AppendSyncedData(data, ref index, eventType);
} }
// Get event size var oldIndex = this.bufferIndex;
ushort eventSize = 0;
for (int i = 0; i < index; i++)
{
eventSize += (ushort)data[i].Length;
}
if (!EnsureSpaceToStoreEvent(eventSize)) var result = Flatten(data, 0, index);
// Validate and fill in event size
var eventSize = result.Length;
if (eventSize > ushort.MaxValue || eventSize < 0)
{ {
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) New event is too large or negative! Size is {eventSize}, maximum allowed is {ushort.MaxValue}");
HandleError(false);
return; return;
} }
var eventSizeBytes = BitConverter.GetBytes(eventSize); var eventSizeBytes = BitConverter.GetBytes((ushort)eventSize);
Array.Copy(eventSizeBytes, 0, data[0], HeaderEventSizeIndex, eventSizeBytes.Length); Array.Copy(eventSizeBytes, 0, result, HeaderEventSizeIndex, eventSizeBytes.Length);
var oldIndex = this.bufferIndex; AppendEventToBuffer(result);
FlattenAndCopy(data, index, buffer, ref this.bufferIndex);
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Prepared event with {eventSize} bytes and timestamp {timestamp} for serialization, index went from {oldIndex} to {this.bufferIndex}"); Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Prepared event with {eventSize} bytes and timestamp {timestamp} for serialization, index went from {oldIndex} to {this.bufferIndex}");
@@ -346,7 +340,7 @@ namespace Marro.PacManUdon
// Event size is added later // Event size is added later
Array.Copy(timestampBytes, 0, header, HeaderTimestampIndex, timestampBytes.Length); Array.Copy(timestampBytes, 0, header, HeaderTimestampIndex, timestampBytes.Length);
header[HeaderEventIdIndex] = eventId; header[HeaderEventIdIndex] = eventId;
header[HeaderEventTypeIndex] = GameManager.Int32ToByte((int)eventType); header[HeaderEventTypeIndex] = Int32ToByte((int)eventType);
// Initialize event container // Initialize event container
data = new byte[maxSize][]; data = new byte[maxSize][];
@@ -375,7 +369,7 @@ namespace Marro.PacManUdon
private void StoreIncomingData() private void StoreIncomingData()
{ {
if (networkedData.Length == 0) if (networkedData == null || networkedData.Length == 0)
{ {
return; // Nothing to store return; // Nothing to store
} }
@@ -401,7 +395,7 @@ namespace Marro.PacManUdon
return; return;
} }
eventSize = networkedData[index + HeaderEventSizeIndex]; eventSize = GetEventSizeFromHeader(networkedData, index);
if (length - index < eventSize) if (length - index < eventSize)
{ {
@@ -410,11 +404,20 @@ namespace Marro.PacManUdon
return; return;
} }
var eventType = (NetworkEventType)networkedData[index + HeaderEventTypeIndex]; if (length - index < HeaderLength)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) {nameof(StoreIncomingData)}: Event size is not long enough to form a complete event! {nameof(eventSize)}: {eventSize}, minimum needed: {HeaderLength}.");
HandleError(false);
return;
}
var @event = GetArrayPart(networkedData, index, eventSize);
var eventType = GetEventTypeFromHeader(@event);
if (eventType == NetworkEventType.FullSync) if (eventType == NetworkEventType.FullSync)
{ {
ProcessIncomingFullSync(index, eventSize); // Immediately process full sync ProcessIncomingFullSync(@event); // Immediately process full sync
continue; continue;
} }
@@ -424,8 +427,8 @@ namespace Marro.PacManUdon
continue; continue;
} }
var timestamp = networkedData[index + HeaderTimestampIndex]; var timestamp = GetTimestampFromHeader(@event);
var eventId = networkedData[index + HeaderEventIdIndex]; var eventId = GetEventIdFromHeader(@event);
if (timestamp == lastEventTimestamp if (timestamp == lastEventTimestamp
&& eventId == lastEventId) && eventId == lastEventId)
@@ -441,26 +444,27 @@ namespace Marro.PacManUdon
return; return;
} }
AppendEventToBuffer(index, eventSize); AppendEventToBuffer(@event);
lastEventTimestamp = timestamp; lastEventTimestamp = timestamp;
lastEventId = eventId; lastEventId = eventId;
} }
UpdateNextEventTime();
} }
private void ProcessIncomingFullSync(int index, int size) private void ProcessIncomingFullSync(byte[] @event)
{ {
// Intentionally not doing a buffer size check here, since this is not appended to the buffer // Intentionally not doing a buffer size check here, since this is not appended to the buffer
// (and there is no good way to continue if this event is too large) // (and there is no good way to continue if this event is too large)
// Clear buffer and copy the full sync into it // Clear buffer and put the full sync into it
buffer = new byte[size]; ClearBuffer();
Array.Copy(networkedData, index, buffer, 0, size); AppendEventToBuffer(@event);
this.bufferIndex = size;
// Sync up to the time in the full sync // Sync up to the time in the full sync
var timestamp = BitConverter.ToUInt32(networkedData, index + HeaderTimestampIndex); var timestamp = GetTimestampFromHeader(@event);
var eventId = networkedData[index + HeaderEventIdIndex]; var eventId = GetEventIdFromHeader(@event);
SyncToTimestamp(timestamp, eventId); SyncToTimestamp(timestamp, eventId);
// Immediately apply the full sync // Immediately apply the full sync
@@ -481,11 +485,13 @@ namespace Marro.PacManUdon
private void ProcessIncomingEvent() private void ProcessIncomingEvent()
{ {
var eventTime = TimestampToTime(BitConverter.ToUInt32(buffer, HeaderTimestampIndex)); var @event = NextEvent;
var eventType = (NetworkEventType)buffer[HeaderEventTypeIndex];
var timestamp = GetTimestampFromHeader(@event);
var eventType = GetEventTypeFromHeader(@event);
var index = (int)HeaderLength; // Skip header var index = (int)HeaderLength; // Skip header
ProgressSyncedTime(eventTime); ProgressSyncedTime(timestamp);
foreach (var obj in syncedObjects) foreach (var obj in syncedObjects)
{ {
@@ -494,7 +500,7 @@ namespace Marro.PacManUdon
foreach (var obj in syncedObjects) foreach (var obj in syncedObjects)
{ {
var success = obj.SetSyncedData(buffer, ref index, eventType); var success = obj.SetSyncedData(@event, ref index, eventType);
if (!success) if (!success)
{ {
@@ -502,16 +508,9 @@ namespace Marro.PacManUdon
HandleError(true); HandleError(true);
return; return;
} }
if (index > this.bufferIndex)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Buffer overflow during {nameof(SyncedObject.SetSyncedData)} for {obj.name} in event type {eventType}!");
HandleError(true);
return;
}
} }
var eventSize = BitConverter.ToUInt16(buffer, HeaderEventSizeIndex); var eventSize = GetEventSizeFromHeader(@event);
if (index != eventSize) if (index != eventSize)
{ {
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Amount of data read does not match event size! Expected {eventSize}, read {index}."); Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Amount of data read does not match event size! Expected {eventSize}, read {index}.");
@@ -519,7 +518,7 @@ namespace Marro.PacManUdon
return; return;
} }
RemoveProcessedDataFromBuffer(index); RemoveProcessedDataFromBuffer(1);
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Processed incoming event! Total {index} bytes."); Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Processed incoming event! Total {index} bytes.");
@@ -530,7 +529,7 @@ namespace Marro.PacManUdon
#region Buffer #region Buffer
private void ClearBuffer() private void ClearBuffer()
{ {
buffer = new byte[BufferMaxSizeBytes]; buffer = new byte[BufferMaxTotalEvents][];
bufferIndex = 0; bufferIndex = 0;
} }
@@ -538,69 +537,26 @@ namespace Marro.PacManUdon
{ {
var oldBuffer = buffer; var oldBuffer = buffer;
bufferIndex -= amountProcessed; bufferIndex -= amountProcessed;
buffer = new byte[BufferMaxSizeBytes]; buffer = new byte[BufferMaxTotalEvents][];
Array.Copy(oldBuffer, amountProcessed, buffer, 0, bufferIndex); Array.Copy(oldBuffer, amountProcessed, buffer, 0, bufferIndex);
} }
private bool IncreaseBufferSize(int newSize) private bool AppendEventToBuffer(byte[] @event)
{ {
if (newSize < buffer.Length) if (bufferIndex >= BufferMaxTotalEvents)
{ {
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Cannot decrease the size of the buffer!"); Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Buffer not large enough to store event! Maximum event count: {BufferMaxTotalEvents}.");
HandleError(true);
return false; return false;
} }
if (newSize > BufferMaxSizeBytes) buffer[bufferIndex++] = @event;
{
return false;
}
var oldBuffer = buffer;
buffer = new byte[newSize];
oldBuffer.CopyTo(buffer, 0);
return true; return true;
} }
private bool EnsureSpaceToStoreEvent(int eventSize) private byte[] NextEvent =>
{ buffer[0];
if (bufferIndex + eventSize <= buffer.Length)
{
return true; // Enough space!
}
var newBufferSize = ((bufferIndex + eventSize) / BufferIncrementSizeBytes + 1) * BufferIncrementSizeBytes;
var success = IncreaseBufferSize(newBufferSize);
if (success)
{
return true;
}
if (bufferIndex == 0)
{
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Buffer is not large enough to store event!");
}
else
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Too much data in buffer to store event!");
}
HandleError(false);
return false;
}
private void AppendEventToBuffer(int index, int size)
{
if (!EnsureSpaceToStoreEvent(size))
{
return;
}
Array.Copy(networkedData, index, buffer, this.bufferIndex, size);
this.bufferIndex += size;
UpdateNextEventTime();
}
#endregion #endregion
#region Time #region Time
@@ -640,7 +596,7 @@ namespace Marro.PacManUdon
return; return;
} }
var nextEventTime = TimestampToTime(BitConverter.ToUInt32(buffer, HeaderTimestampIndex)); var nextEventTime = TimestampToTime(GetTimestampFromHeader(NextEvent));
if (ignoreOrder || nextEventTime >= this.nextEventTime) if (ignoreOrder || nextEventTime >= this.nextEventTime)
{ {
this.nextEventTime = nextEventTime; this.nextEventTime = nextEventTime;
@@ -676,6 +632,18 @@ namespace Marro.PacManUdon
return currentEventId; return currentEventId;
} }
public static ushort GetEventSizeFromHeader(byte[] @event, int eventIndex = 0)
=> BitConverter.ToUInt16(@event, eventIndex + HeaderEventSizeIndex);
public static NetworkEventType GetEventTypeFromHeader(byte[] @event, int eventIndex = 0) =>
(NetworkEventType)@event[eventIndex + HeaderEventTypeIndex];
public static uint GetTimestampFromHeader(byte[] @event, int eventIndex = 0) =>
BitConverter.ToUInt32(@event, eventIndex + HeaderTimestampIndex);
public static byte GetEventIdFromHeader(byte[] @event, int eventIndex = 0) =>
@event[eventIndex + HeaderEventIdIndex];
#endregion #endregion
#region VRC events #region VRC events
@@ -684,12 +652,24 @@ namespace Marro.PacManUdon
SetOwner(newOwner == Networking.LocalPlayer); SetOwner(newOwner == Networking.LocalPlayer);
} }
private int indexAtLastSerialization = 0;
public override void OnPreSerialization() public override void OnPreSerialization()
{ {
if (!Ready)
{
return;
}
if (isOwner) if (isOwner)
{ {
networkedData = new byte[bufferIndex]; if (buffer == null || bufferIndex == 0)
Array.Copy(buffer, networkedData, bufferIndex); {
return;
}
networkedData = Flatten(buffer, 0, bufferIndex);
indexAtLastSerialization = bufferIndex;
} }
else else
{ {
@@ -699,6 +679,11 @@ namespace Marro.PacManUdon
public override void OnPostSerialization(SerializationResult result) public override void OnPostSerialization(SerializationResult result)
{ {
if (!Ready)
{
return;
}
if (!result.success) if (!result.success)
{ {
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Serialization failed! Tried to send {result.byteCount} bytes."); Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Serialization failed! Tried to send {result.byteCount} bytes.");
@@ -713,16 +698,18 @@ namespace Marro.PacManUdon
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Serialized with {networkedData.Length} bytes!\nBytes sent:\n{BytesToString(networkedData)}"); Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Serialized with {networkedData.Length} bytes!\nBytes sent:\n{BytesToString(networkedData)}");
// Remove all transferred data from the buffer, leaving data that came in after serialization // Remove all transferred data from the buffer, leaving data that came in after serialization
RemoveProcessedDataFromBuffer(networkedData.Length); RemoveProcessedDataFromBuffer(indexAtLastSerialization);
networkedData = null; networkedData = new byte[0];
} }
public override void OnDeserialization() public override void OnDeserialization()
{ {
if (!isOwner) if (!Ready || isOwner)
{ {
StoreIncomingData(); return;
} }
StoreIncomingData();
} }
#endregion #endregion
@@ -738,15 +725,42 @@ namespace Marro.PacManUdon
return sb.ToString(); return sb.ToString();
} }
private static void FlattenAndCopy(byte[][] data, int length, byte[] target, ref int index) private static int GetFlattenedSize(byte[][] data, int start, int length)
{ {
for (int i = 0; i < length; i++) var size = 0;
for (int i = start; i < start + length; i++)
{ {
var values = data[i]; size += data[i].Length;
Array.Copy(values, 0, target, index, values.Length);
index += values.Length;
} }
return size;
} }
private static byte[] Flatten(byte[][] data, int start, int length)
{
var finalLength = GetFlattenedSize(data, start, length);
var result = new byte[finalLength];
int resultIndex = 0;
for (int sourceIndex = start; sourceIndex < start + length; sourceIndex++)
{
var array = data[sourceIndex];
Array.Copy(array, 0, result, resultIndex, array.Length);
resultIndex += array.Length;
}
return result;
}
private static byte[] GetArrayPart(byte[] data, int start, int length)
{
var result = new byte[length];
Array.Copy(data, start, result, 0, length);
return result;
}
public static byte Int32ToByte(int value) =>
(byte)value; // Doing this inline causes an error...?
#endregion #endregion
#region Debug #region Debug
@@ -759,6 +773,7 @@ namespace Marro.PacManUdon
{ {
debugOutput.text += $"{nameof(NetworkManager)}:\n" + debugOutput.text += $"{nameof(NetworkManager)}:\n" +
$"IsOwner: {isOwner}\n" + $"IsOwner: {isOwner}\n" +
$"Ready: {Ready}\n" +
$"Time.fixedTime: {Time.fixedTime}\n" + $"Time.fixedTime: {Time.fixedTime}\n" +
$"offsetTime: {offsetTime}\n" + $"offsetTime: {offsetTime}\n" +
$"internalTime: {internalTime}\n" + $"internalTime: {internalTime}\n" +