Kinda working refactor
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using TMPro;
|
||||
using UdonSharp;
|
||||
@@ -44,11 +46,7 @@ namespace Marro.PacManUdon
|
||||
/// <summary>
|
||||
/// The maximum size of the buffer in bytes.
|
||||
/// </summary>
|
||||
private const int BufferMaxSizeBytes = 10000;
|
||||
/// <summary>
|
||||
/// How many bytes to increase the buffer size by if the current one is not enough.
|
||||
/// </summary>
|
||||
private const int BufferIncrementSizeBytes = 1000;
|
||||
private const int BufferMaxTotalEvents = 255;
|
||||
|
||||
/// <summary>
|
||||
/// The index in an event where the event size is stored.
|
||||
@@ -71,10 +69,6 @@ namespace Marro.PacManUdon
|
||||
/// </summary>
|
||||
private const ushort HeaderLength = 8;
|
||||
/// <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.
|
||||
/// </summary>
|
||||
private const ushort HeaderPartsCount = 4;
|
||||
@@ -86,7 +80,7 @@ namespace Marro.PacManUdon
|
||||
/// <summary>
|
||||
/// The zero value of a timestamp. Anything below this value is negative.
|
||||
/// </summary>
|
||||
private const uint TimestampZeroValue = 1000;
|
||||
private const uint TimestampZeroValue = 10000;
|
||||
/// <summary>
|
||||
/// The delay at which the receiving side replays events.
|
||||
/// </summary>
|
||||
@@ -140,7 +134,7 @@ namespace Marro.PacManUdon
|
||||
/// <summary>
|
||||
/// Main buffer of data to be transmitted or processed
|
||||
/// </summary>
|
||||
private byte[] buffer;
|
||||
private byte[][] buffer;
|
||||
/// <summary>
|
||||
/// Index of <see cref="buffer"/>.
|
||||
/// </summary>
|
||||
@@ -200,7 +194,7 @@ namespace Marro.PacManUdon
|
||||
|
||||
SetOwner(Networking.IsOwner(gameObject));
|
||||
|
||||
buffer = new byte[BufferIncrementSizeBytes];
|
||||
buffer = new byte[BufferMaxTotalEvents][];
|
||||
bufferIndex = 0;
|
||||
isSynced = isOwner; // Owner is always synced
|
||||
retriesWithoutSuccess = 0;
|
||||
@@ -300,31 +294,31 @@ namespace Marro.PacManUdon
|
||||
|
||||
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)
|
||||
{
|
||||
obj.AppendSyncedData(data, ref index, eventType);
|
||||
}
|
||||
|
||||
// Get event size
|
||||
ushort eventSize = 0;
|
||||
for (int i = 0; i < index; i++)
|
||||
{
|
||||
eventSize += (ushort)data[i].Length;
|
||||
}
|
||||
var oldIndex = this.bufferIndex;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
var eventSizeBytes = BitConverter.GetBytes(eventSize);
|
||||
Array.Copy(eventSizeBytes, 0, data[0], HeaderEventSizeIndex, eventSizeBytes.Length);
|
||||
var eventSizeBytes = BitConverter.GetBytes((ushort)eventSize);
|
||||
Array.Copy(eventSizeBytes, 0, result, HeaderEventSizeIndex, eventSizeBytes.Length);
|
||||
|
||||
var oldIndex = this.bufferIndex;
|
||||
|
||||
FlattenAndCopy(data, index, buffer, ref this.bufferIndex);
|
||||
AppendEventToBuffer(result);
|
||||
|
||||
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
|
||||
Array.Copy(timestampBytes, 0, header, HeaderTimestampIndex, timestampBytes.Length);
|
||||
header[HeaderEventIdIndex] = eventId;
|
||||
header[HeaderEventTypeIndex] = GameManager.Int32ToByte((int)eventType);
|
||||
header[HeaderEventTypeIndex] = Int32ToByte((int)eventType);
|
||||
|
||||
// Initialize event container
|
||||
data = new byte[maxSize][];
|
||||
@@ -375,7 +369,7 @@ namespace Marro.PacManUdon
|
||||
|
||||
private void StoreIncomingData()
|
||||
{
|
||||
if (networkedData.Length == 0)
|
||||
if (networkedData == null || networkedData.Length == 0)
|
||||
{
|
||||
return; // Nothing to store
|
||||
}
|
||||
@@ -401,7 +395,7 @@ namespace Marro.PacManUdon
|
||||
return;
|
||||
}
|
||||
|
||||
eventSize = networkedData[index + HeaderEventSizeIndex];
|
||||
eventSize = GetEventSizeFromHeader(networkedData, index);
|
||||
|
||||
if (length - index < eventSize)
|
||||
{
|
||||
@@ -410,11 +404,20 @@ namespace Marro.PacManUdon
|
||||
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)
|
||||
{
|
||||
ProcessIncomingFullSync(index, eventSize); // Immediately process full sync
|
||||
ProcessIncomingFullSync(@event); // Immediately process full sync
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -424,8 +427,8 @@ namespace Marro.PacManUdon
|
||||
continue;
|
||||
}
|
||||
|
||||
var timestamp = networkedData[index + HeaderTimestampIndex];
|
||||
var eventId = networkedData[index + HeaderEventIdIndex];
|
||||
var timestamp = GetTimestampFromHeader(@event);
|
||||
var eventId = GetEventIdFromHeader(@event);
|
||||
|
||||
if (timestamp == lastEventTimestamp
|
||||
&& eventId == lastEventId)
|
||||
@@ -441,26 +444,27 @@ namespace Marro.PacManUdon
|
||||
return;
|
||||
}
|
||||
|
||||
AppendEventToBuffer(index, eventSize);
|
||||
AppendEventToBuffer(@event);
|
||||
|
||||
lastEventTimestamp = timestamp;
|
||||
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
|
||||
// (and there is no good way to continue if this event is too large)
|
||||
|
||||
// Clear buffer and copy the full sync into it
|
||||
buffer = new byte[size];
|
||||
Array.Copy(networkedData, index, buffer, 0, size);
|
||||
this.bufferIndex = size;
|
||||
// Clear buffer and put the full sync into it
|
||||
ClearBuffer();
|
||||
AppendEventToBuffer(@event);
|
||||
|
||||
// Sync up to the time in the full sync
|
||||
var timestamp = BitConverter.ToUInt32(networkedData, index + HeaderTimestampIndex);
|
||||
var eventId = networkedData[index + HeaderEventIdIndex];
|
||||
var timestamp = GetTimestampFromHeader(@event);
|
||||
var eventId = GetEventIdFromHeader(@event);
|
||||
SyncToTimestamp(timestamp, eventId);
|
||||
|
||||
// Immediately apply the full sync
|
||||
@@ -481,11 +485,13 @@ namespace Marro.PacManUdon
|
||||
|
||||
private void ProcessIncomingEvent()
|
||||
{
|
||||
var eventTime = TimestampToTime(BitConverter.ToUInt32(buffer, HeaderTimestampIndex));
|
||||
var eventType = (NetworkEventType)buffer[HeaderEventTypeIndex];
|
||||
var @event = NextEvent;
|
||||
|
||||
var timestamp = GetTimestampFromHeader(@event);
|
||||
var eventType = GetEventTypeFromHeader(@event);
|
||||
var index = (int)HeaderLength; // Skip header
|
||||
|
||||
ProgressSyncedTime(eventTime);
|
||||
ProgressSyncedTime(timestamp);
|
||||
|
||||
foreach (var obj in syncedObjects)
|
||||
{
|
||||
@@ -494,7 +500,7 @@ namespace Marro.PacManUdon
|
||||
|
||||
foreach (var obj in syncedObjects)
|
||||
{
|
||||
var success = obj.SetSyncedData(buffer, ref index, eventType);
|
||||
var success = obj.SetSyncedData(@event, ref index, eventType);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
@@ -502,16 +508,9 @@ namespace Marro.PacManUdon
|
||||
HandleError(true);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
RemoveProcessedDataFromBuffer(index);
|
||||
RemoveProcessedDataFromBuffer(1);
|
||||
|
||||
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Processed incoming event! Total {index} bytes.");
|
||||
|
||||
@@ -530,7 +529,7 @@ namespace Marro.PacManUdon
|
||||
#region Buffer
|
||||
private void ClearBuffer()
|
||||
{
|
||||
buffer = new byte[BufferMaxSizeBytes];
|
||||
buffer = new byte[BufferMaxTotalEvents][];
|
||||
bufferIndex = 0;
|
||||
}
|
||||
|
||||
@@ -538,69 +537,26 @@ namespace Marro.PacManUdon
|
||||
{
|
||||
var oldBuffer = buffer;
|
||||
bufferIndex -= amountProcessed;
|
||||
buffer = new byte[BufferMaxSizeBytes];
|
||||
buffer = new byte[BufferMaxTotalEvents][];
|
||||
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;
|
||||
}
|
||||
|
||||
if (newSize > BufferMaxSizeBytes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var oldBuffer = buffer;
|
||||
buffer = new byte[newSize];
|
||||
oldBuffer.CopyTo(buffer, 0);
|
||||
buffer[bufferIndex++] = @event;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool EnsureSpaceToStoreEvent(int eventSize)
|
||||
{
|
||||
if (bufferIndex + eventSize <= buffer.Length)
|
||||
{
|
||||
return true; // Enough space!
|
||||
}
|
||||
private byte[] NextEvent =>
|
||||
buffer[0];
|
||||
|
||||
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
|
||||
|
||||
#region Time
|
||||
@@ -640,7 +596,7 @@ namespace Marro.PacManUdon
|
||||
return;
|
||||
}
|
||||
|
||||
var nextEventTime = TimestampToTime(BitConverter.ToUInt32(buffer, HeaderTimestampIndex));
|
||||
var nextEventTime = TimestampToTime(GetTimestampFromHeader(NextEvent));
|
||||
if (ignoreOrder || nextEventTime >= this.nextEventTime)
|
||||
{
|
||||
this.nextEventTime = nextEventTime;
|
||||
@@ -676,6 +632,18 @@ namespace Marro.PacManUdon
|
||||
|
||||
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
|
||||
|
||||
#region VRC events
|
||||
@@ -684,12 +652,24 @@ namespace Marro.PacManUdon
|
||||
SetOwner(newOwner == Networking.LocalPlayer);
|
||||
}
|
||||
|
||||
private int indexAtLastSerialization = 0;
|
||||
|
||||
public override void OnPreSerialization()
|
||||
{
|
||||
if (!Ready)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isOwner)
|
||||
{
|
||||
networkedData = new byte[bufferIndex];
|
||||
Array.Copy(buffer, networkedData, bufferIndex);
|
||||
if (buffer == null || bufferIndex == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
networkedData = Flatten(buffer, 0, bufferIndex);
|
||||
indexAtLastSerialization = bufferIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -699,6 +679,11 @@ namespace Marro.PacManUdon
|
||||
|
||||
public override void OnPostSerialization(SerializationResult result)
|
||||
{
|
||||
if (!Ready)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.success)
|
||||
{
|
||||
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)}");
|
||||
|
||||
// Remove all transferred data from the buffer, leaving data that came in after serialization
|
||||
RemoveProcessedDataFromBuffer(networkedData.Length);
|
||||
networkedData = null;
|
||||
RemoveProcessedDataFromBuffer(indexAtLastSerialization);
|
||||
networkedData = new byte[0];
|
||||
}
|
||||
|
||||
public override void OnDeserialization()
|
||||
{
|
||||
if (!isOwner)
|
||||
if (!Ready || isOwner)
|
||||
{
|
||||
StoreIncomingData();
|
||||
return;
|
||||
}
|
||||
|
||||
StoreIncomingData();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -738,15 +725,42 @@ namespace Marro.PacManUdon
|
||||
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];
|
||||
Array.Copy(values, 0, target, index, values.Length);
|
||||
index += values.Length;
|
||||
size += data[i].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
|
||||
|
||||
#region Debug
|
||||
@@ -759,6 +773,7 @@ namespace Marro.PacManUdon
|
||||
{
|
||||
debugOutput.text += $"{nameof(NetworkManager)}:\n" +
|
||||
$"IsOwner: {isOwner}\n" +
|
||||
$"Ready: {Ready}\n" +
|
||||
$"Time.fixedTime: {Time.fixedTime}\n" +
|
||||
$"offsetTime: {offsetTime}\n" +
|
||||
$"internalTime: {internalTime}\n" +
|
||||
|
||||
Reference in New Issue
Block a user