diff --git a/Assets/Scripts/GameManager.cs b/Assets/Scripts/GameManager.cs index e7721cb..4477c60 100644 --- a/Assets/Scripts/GameManager.cs +++ b/Assets/Scripts/GameManager.cs @@ -424,9 +424,9 @@ namespace Marro.PacManUdon 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++] = new byte[] { Int32ToByte((int)currentTimeSequence) }; + data[offset++] = new byte[] { NetworkManager.Int32ToByte((int)currentTimeSequence) }; data[offset++] = BitConverter.GetBytes(timeSequenceProgress); } @@ -496,9 +496,5 @@ namespace Marro.PacManUdon } 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... } } \ No newline at end of file diff --git a/Assets/Scripts/NetworkManager.asset b/Assets/Scripts/NetworkManager.asset index aaec9c5..45681d1 100644 --- a/Assets/Scripts/NetworkManager.asset +++ b/Assets/Scripts/NetworkManager.asset @@ -43,7 +43,7 @@ MonoBehaviour: Data: - Name: Entry: 12 - Data: 17 + Data: 18 - Name: Entry: 7 Data: @@ -539,6 +539,114 @@ MonoBehaviour: - Name: k__BackingField Entry: 7 Data: 29|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Byte[][], mscorlib + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 7 + Data: 30|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Object[], mscorlib + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: 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: k__BackingField + Entry: 1 + Data: bufferIndex + - Name: k__BackingField + Entry: 9 + Data: 26 + - Name: k__BackingField + Entry: 9 + Data: 26 + - Name: k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: 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: k__BackingField + Entry: 1 + Data: networkedData + - Name: k__BackingField + Entry: 7 + Data: 35|System.RuntimeType, mscorlib - Name: Entry: 1 Data: System.Byte[], mscorlib @@ -547,103 +655,7 @@ MonoBehaviour: Data: - Name: k__BackingField Entry: 9 - Data: 29 - - Name: k__BackingField - Entry: 7 - Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib - - Name: - Entry: 6 - Data: - - Name: - Entry: 8 - Data: - - Name: 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: k__BackingField - Entry: 1 - Data: bufferIndex - - Name: k__BackingField - Entry: 9 - Data: 26 - - Name: k__BackingField - Entry: 9 - Data: 26 - - Name: k__BackingField - Entry: 7 - Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib - - Name: - Entry: 6 - Data: - - Name: - Entry: 8 - Data: - - Name: 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: k__BackingField - Entry: 1 - Data: networkedData - - Name: k__BackingField - Entry: 9 - Data: 29 - - Name: k__BackingField - Entry: 9 - Data: 29 + Data: 35 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -658,13 +670,13 @@ MonoBehaviour: Data: false - Name: _fieldAttributes 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: Entry: 12 Data: 1 - Name: Entry: 7 - Data: 35|UdonSharp.UdonSyncedAttribute, UdonSharp.Runtime + Data: 37|UdonSharp.UdonSyncedAttribute, UdonSharp.Runtime - Name: Entry: 8 Data: @@ -686,66 +698,18 @@ MonoBehaviour: - Name: $k Entry: 1 Data: k__BackingField - - Name: $v - Entry: 7 - Data: 36|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - - Name: k__BackingField - Entry: 1 - Data: k__BackingField - - Name: k__BackingField - Entry: 9 - Data: 8 - - Name: k__BackingField - Entry: 9 - Data: 8 - - Name: k__BackingField - Entry: 7 - Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib - - Name: - Entry: 6 - Data: - - Name: - Entry: 8 - Data: - - Name: 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: k__BackingField - Name: $v Entry: 7 Data: 38|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: k__BackingField + Data: k__BackingField - Name: k__BackingField Entry: 9 - Data: 13 + Data: 8 - Name: k__BackingField Entry: 9 - Data: 13 + Data: 8 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -781,13 +745,13 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data:
k__BackingField + Data: k__BackingField - Name: $v Entry: 7 Data: 40|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data:
k__BackingField + Data: k__BackingField - Name: k__BackingField Entry: 9 Data: 13 @@ -829,19 +793,19 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: k__BackingField + Data:
k__BackingField - Name: $v Entry: 7 Data: 42|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: k__BackingField + Data:
k__BackingField - Name: k__BackingField Entry: 9 - Data: 8 + Data: 13 - Name: k__BackingField Entry: 9 - Data: 8 + Data: 13 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -877,16 +841,112 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: DebugImageToIndicateOwner + Data: k__BackingField - Name: $v Entry: 7 Data: 44|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: k__BackingField + - Name: k__BackingField + Entry: 9 + Data: 8 + - Name: k__BackingField + Entry: 9 + Data: 8 + - Name: k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: 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: k__BackingField + Entry: 1 + Data: indexAtLastSerialization + - Name: k__BackingField + Entry: 9 + Data: 26 + - Name: k__BackingField + Entry: 9 + Data: 26 + - Name: k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: 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: k__BackingField Entry: 1 Data: DebugImageToIndicateOwner - Name: k__BackingField Entry: 7 - Data: 45|System.RuntimeType, mscorlib + Data: 49|System.RuntimeType, mscorlib - Name: Entry: 1 Data: UnityEngine.Animator, UnityEngine.AnimationModule @@ -895,7 +955,7 @@ MonoBehaviour: Data: - Name: k__BackingField Entry: 9 - Data: 45 + Data: 49 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -910,13 +970,13 @@ MonoBehaviour: Data: true - Name: _fieldAttributes 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: Entry: 12 Data: 1 - Name: Entry: 7 - Data: 47|UnityEngine.SerializeField, UnityEngine.CoreModule + Data: 51|UnityEngine.SerializeField, UnityEngine.CoreModule - Name: Entry: 8 Data: diff --git a/Assets/Scripts/NetworkManager.cs b/Assets/Scripts/NetworkManager.cs index 12ad78d..ec7a283 100644 --- a/Assets/Scripts/NetworkManager.cs +++ b/Assets/Scripts/NetworkManager.cs @@ -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 /// /// The maximum size of the buffer in bytes. /// - private const int BufferMaxSizeBytes = 10000; - /// - /// How many bytes to increase the buffer size by if the current one is not enough. - /// - private const int BufferIncrementSizeBytes = 1000; + private const int BufferMaxTotalEvents = 255; /// /// The index in an event where the event size is stored. @@ -71,10 +69,6 @@ namespace Marro.PacManUdon /// private const ushort HeaderLength = 8; /// - /// The length of the event size part of the header, in bytes. - /// - private const ushort HeaderEventSizeBytes = 2; - /// /// The amount of parts of which the header consists. /// private const ushort HeaderPartsCount = 4; @@ -86,7 +80,7 @@ namespace Marro.PacManUdon /// /// The zero value of a timestamp. Anything below this value is negative. /// - private const uint TimestampZeroValue = 1000; + private const uint TimestampZeroValue = 10000; /// /// The delay at which the receiving side replays events. /// @@ -140,7 +134,7 @@ namespace Marro.PacManUdon /// /// Main buffer of data to be transmitted or processed /// - private byte[] buffer; + private byte[][] buffer; /// /// Index of . /// @@ -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" +