Compare commits

...

5 Commits

Author SHA1 Message Date
bcf830d52d Cleaned up and more use of Ready 2026-01-08 20:11:21 +01:00
af87ffea42 Small fix 2026-01-08 19:51:11 +01:00
14fc9ea576 Timestamp is now float 2026-01-08 19:45:22 +01:00
630dc5a176 Kinda working refactor 2026-01-05 20:10:13 +01:00
2636e65e4d Some handling of dropped packages 2026-01-04 19:06:03 +01:00
8 changed files with 1655 additions and 1390 deletions

View File

@@ -266,6 +266,37 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2406178} m_GameObject: {fileID: 2406178}
m_CullTransparentMesh: 1 m_CullTransparentMesh: 1
--- !u!1 &2841571
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2841572}
m_Layer: 0
m_Name: Resend previous events
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2841572
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2841571}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 297676220}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &6734103 --- !u!1001 &6734103
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -9639,6 +9670,42 @@ PrefabInstance:
m_AddedGameObjects: [] m_AddedGameObjects: []
m_AddedComponents: [] m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 00a825a5aeafee94789192f61cbb3a5a, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 00a825a5aeafee94789192f61cbb3a5a, type: 3}
--- !u!1 &297676219
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 297676220}
m_Layer: 0
m_Name: NetworkManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &297676220
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 297676219}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1897221841}
- {fileID: 2841572}
- {fileID: 963448677}
- {fileID: 1334822256}
- {fileID: 1683006206}
m_Father: {fileID: 1886023632}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &300095180 --- !u!1001 &300095180
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -28642,6 +28709,37 @@ Transform:
m_CorrespondingSourceObject: {fileID: 1315692994360949719, guid: 00a825a5aeafee94789192f61cbb3a5a, type: 3} m_CorrespondingSourceObject: {fileID: 1315692994360949719, guid: 00a825a5aeafee94789192f61cbb3a5a, type: 3}
m_PrefabInstance: {fileID: 1641300668} m_PrefabInstance: {fileID: 1641300668}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
--- !u!1 &963448676
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 963448677}
m_Layer: 0
m_Name: Ping
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &963448677
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 963448676}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 297676220}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &964231232 stripped --- !u!1 &964231232 stripped
GameObject: GameObject:
m_CorrespondingSourceObject: {fileID: 4099390335584803315, guid: 00a825a5aeafee94789192f61cbb3a5a, type: 3} m_CorrespondingSourceObject: {fileID: 4099390335584803315, guid: 00a825a5aeafee94789192f61cbb3a5a, type: 3}
@@ -41660,6 +41758,37 @@ GameObject:
m_CorrespondingSourceObject: {fileID: 1914595051839510733, guid: 9fbd72f5bc3c5434a87ab8539789c584, type: 3} m_CorrespondingSourceObject: {fileID: 1914595051839510733, guid: 9fbd72f5bc3c5434a87ab8539789c584, type: 3}
m_PrefabInstance: {fileID: 8042777216032092028} m_PrefabInstance: {fileID: 8042777216032092028}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
--- !u!1 &1334822255
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1334822256}
m_Layer: 0
m_Name: FullSync respects delay
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1334822256
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1334822255}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 297676220}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &1335132404 --- !u!1001 &1335132404
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -51668,6 +51797,37 @@ PrefabInstance:
m_AddedGameObjects: [] m_AddedGameObjects: []
m_AddedComponents: [] m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 00a825a5aeafee94789192f61cbb3a5a, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 00a825a5aeafee94789192f61cbb3a5a, type: 3}
--- !u!1 &1683006205
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1683006206}
m_Layer: 0
m_Name: Store events in separate arrays
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1683006206
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1683006205}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 297676220}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!4 &1683500364 stripped --- !u!4 &1683500364 stripped
Transform: Transform:
m_CorrespondingSourceObject: {fileID: 1315692994360949719, guid: 00a825a5aeafee94789192f61cbb3a5a, type: 3} m_CorrespondingSourceObject: {fileID: 1315692994360949719, guid: 00a825a5aeafee94789192f61cbb3a5a, type: 3}
@@ -58786,6 +58946,7 @@ Transform:
- {fileID: 712073434} - {fileID: 712073434}
- {fileID: 106401850} - {fileID: 106401850}
- {fileID: 851913432} - {fileID: 851913432}
- {fileID: 297676220}
- {fileID: 1961479820} - {fileID: 1961479820}
- {fileID: 2129311453} - {fileID: 2129311453}
- {fileID: 2142346958} - {fileID: 2142346958}
@@ -58899,12 +59060,12 @@ Transform:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1897221840} m_GameObject: {fileID: 1897221840}
serializedVersion: 2 serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 1961479820} m_Father: {fileID: 297676220}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1898242099 stripped --- !u!1 &1898242099 stripped
GameObject: GameObject:
@@ -60490,7 +60651,6 @@ Transform:
- {fileID: 2030126881} - {fileID: 2030126881}
- {fileID: 2103220969} - {fileID: 2103220969}
- {fileID: 455444785} - {fileID: 455444785}
- {fileID: 1897221841}
- {fileID: 147662346} - {fileID: 147662346}
- {fileID: 29433776} - {fileID: 29433776}
m_Father: {fileID: 1886023632} m_Father: {fileID: 1886023632}

File diff suppressed because it is too large Load Diff

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:
@@ -115,19 +115,19 @@ MonoBehaviour:
Data: Data:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: isOwner Data: offsetTime
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 7|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 7|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: isOwner Data: offsetTime
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 7 Entry: 7
Data: 8|System.RuntimeType, mscorlib Data: 8|System.RuntimeType, mscorlib
- Name: - Name:
Entry: 1 Entry: 1
Data: System.Boolean, mscorlib Data: System.Single, mscorlib
- Name: - Name:
Entry: 8 Entry: 8
Data: Data:
@@ -169,13 +169,13 @@ MonoBehaviour:
Data: Data:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: isSynced Data: internalTime
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 10|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 10|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: isSynced Data: internalTime
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 9 Entry: 9
Data: 8 Data: 8
@@ -217,25 +217,19 @@ MonoBehaviour:
Data: Data:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: offsetTime Data: nextEventTime
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 12|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 12|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: offsetTime Data: nextEventTime
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 7 Entry: 9
Data: 13|System.RuntimeType, mscorlib Data: 8
- Name:
Entry: 1
Data: System.Single, mscorlib
- Name:
Entry: 8
Data:
- 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
@@ -250,7 +244,7 @@ MonoBehaviour:
Data: false Data: false
- Name: _fieldAttributes - Name: _fieldAttributes
Entry: 7 Entry: 7
Data: 14|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib Data: 13|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name: - Name:
Entry: 12 Entry: 12
Data: 0 Data: 0
@@ -271,19 +265,19 @@ MonoBehaviour:
Data: Data:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: internalTime Data: lastEventTimestamp
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 15|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 14|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: internalTime Data: lastEventTimestamp
- 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
@@ -298,7 +292,7 @@ MonoBehaviour:
Data: false Data: false
- Name: _fieldAttributes - Name: _fieldAttributes
Entry: 7 Entry: 7
Data: 16|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib Data: 15|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name: - Name:
Entry: 12 Entry: 12
Data: 0 Data: 0
@@ -319,19 +313,25 @@ MonoBehaviour:
Data: Data:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: nextEventTime Data: lastEventId
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 17|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 16|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: nextEventTime Data: lastEventId
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 9 Entry: 7
Data: 13 Data: 17|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Byte, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField - Name: <SystemType>k__BackingField
Entry: 9 Entry: 9
Data: 13 Data: 17
- 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
@@ -367,19 +367,19 @@ MonoBehaviour:
Data: Data:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: lastEventTimestamp Data: retriesWithoutSuccess
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 19|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 19|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: lastEventTimestamp Data: retriesWithoutSuccess
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 7 Entry: 7
Data: 20|System.RuntimeType, mscorlib Data: 20|System.RuntimeType, mscorlib
- Name: - Name:
Entry: 1 Entry: 1
Data: System.UInt32, mscorlib Data: System.Int32, mscorlib
- Name: - Name:
Entry: 8 Entry: 8
Data: Data:
@@ -421,25 +421,31 @@ MonoBehaviour:
Data: Data:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: lastEventId Data: buffer
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 22|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 22|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: lastEventId Data: buffer
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 7 Entry: 7
Data: 23|System.RuntimeType, mscorlib Data: 23|System.RuntimeType, mscorlib
- Name: - Name:
Entry: 1 Entry: 1
Data: System.Byte, mscorlib Data: System.Byte[][], mscorlib
- Name: - Name:
Entry: 8 Entry: 8
Data: Data:
- Name: <SystemType>k__BackingField - Name: <SystemType>k__BackingField
Entry: 9 Entry: 7
Data: 23 Data: 24|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Object[], mscorlib
- Name:
Entry: 8
Data:
- 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
@@ -454,7 +460,7 @@ MonoBehaviour:
Data: false Data: false
- Name: _fieldAttributes - Name: _fieldAttributes
Entry: 7 Entry: 7
Data: 24|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib Data: 25|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name: - Name:
Entry: 12 Entry: 12
Data: 0 Data: 0
@@ -475,25 +481,19 @@ MonoBehaviour:
Data: Data:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: retriesWithoutSuccess Data: bufferIndex
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 25|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 26|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: retriesWithoutSuccess Data: bufferIndex
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 7 Entry: 9
Data: 26|System.RuntimeType, mscorlib Data: 20
- Name:
Entry: 1
Data: System.Int32, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField - Name: <SystemType>k__BackingField
Entry: 9 Entry: 9
Data: 26 Data: 20
- 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
@@ -529,13 +529,13 @@ MonoBehaviour:
Data: Data:
- Name: $k - Name: $k
Entry: 1 Entry: 1
Data: buffer Data: networkedData
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 28|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 28|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: buffer Data: networkedData
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 7 Entry: 7
Data: 29|System.RuntimeType, mscorlib Data: 29|System.RuntimeType, mscorlib
@@ -551,102 +551,6 @@ MonoBehaviour:
- 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
- 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
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name: - Name:
Entry: 3 Entry: 3
Data: 1 Data: 1
@@ -658,13 +562,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: 30|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: 31|UdonSharp.UdonSyncedAttribute, UdonSharp.Runtime
- Name: - Name:
Entry: 8 Entry: 8
Data: Data:
@@ -688,16 +592,22 @@ MonoBehaviour:
Data: <Ready>k__BackingField Data: <Ready>k__BackingField
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 36|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 32|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: <Ready>k__BackingField Data: <Ready>k__BackingField
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 9 Entry: 7
Data: 8 Data: 33|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Boolean, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField - Name: <SystemType>k__BackingField
Entry: 9 Entry: 9
Data: 8 Data: 33
- 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
@@ -712,7 +622,55 @@ MonoBehaviour:
Data: false Data: false
- Name: _fieldAttributes - Name: _fieldAttributes
Entry: 7 Entry: 7
Data: 37|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib Data: 34|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: <Synced>k__BackingField
- Name: $v
Entry: 7
Data: 35|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: <Synced>k__BackingField
- Name: <UserType>k__BackingField
Entry: 9
Data: 33
- Name: <SystemType>k__BackingField
Entry: 9
Data: 33
- 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: 36|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name: - Name:
Entry: 12 Entry: 12
Data: 0 Data: 0
@@ -736,16 +694,16 @@ MonoBehaviour:
Data: <SyncedTime>k__BackingField Data: <SyncedTime>k__BackingField
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 38|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 37|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: <SyncedTime>k__BackingField Data: <SyncedTime>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
@@ -760,7 +718,7 @@ MonoBehaviour:
Data: false Data: false
- Name: _fieldAttributes - Name: _fieldAttributes
Entry: 7 Entry: 7
Data: 39|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib Data: 38|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name: - Name:
Entry: 12 Entry: 12
Data: 0 Data: 0
@@ -784,16 +742,16 @@ MonoBehaviour:
Data: <Dt>k__BackingField Data: <Dt>k__BackingField
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 40|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 39|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: <Dt>k__BackingField Data: <Dt>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
@@ -808,7 +766,7 @@ MonoBehaviour:
Data: false Data: false
- Name: _fieldAttributes - Name: _fieldAttributes
Entry: 7 Entry: 7
Data: 41|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib Data: 40|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name: - Name:
Entry: 12 Entry: 12
Data: 0 Data: 0
@@ -832,16 +790,16 @@ MonoBehaviour:
Data: <IsEventUpdate>k__BackingField Data: <IsEventUpdate>k__BackingField
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 42|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 41|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField - Name: <Name>k__BackingField
Entry: 1 Entry: 1
Data: <IsEventUpdate>k__BackingField Data: <IsEventUpdate>k__BackingField
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 9 Entry: 9
Data: 8 Data: 33
- Name: <SystemType>k__BackingField - Name: <SystemType>k__BackingField
Entry: 9 Entry: 9
Data: 8 Data: 33
- 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
@@ -856,7 +814,103 @@ MonoBehaviour:
Data: false Data: false
- Name: _fieldAttributes - Name: _fieldAttributes
Entry: 7 Entry: 7
Data: 43|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib Data: 42|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: <IsOwner>k__BackingField
- Name: $v
Entry: 7
Data: 43|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: <IsOwner>k__BackingField
- Name: <UserType>k__BackingField
Entry: 9
Data: 33
- Name: <SystemType>k__BackingField
Entry: 9
Data: 33
- 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: 44|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: 45|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: indexAtLastSerialization
- Name: <UserType>k__BackingField
Entry: 9
Data: 20
- Name: <SystemType>k__BackingField
Entry: 9
Data: 20
- 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: 46|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name: - Name:
Entry: 12 Entry: 12
Data: 0 Data: 0
@@ -880,13 +934,13 @@ MonoBehaviour:
Data: DebugImageToIndicateOwner Data: DebugImageToIndicateOwner
- Name: $v - Name: $v
Entry: 7 Entry: 7
Data: 44|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor Data: 47|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: 48|System.RuntimeType, mscorlib
- Name: - Name:
Entry: 1 Entry: 1
Data: UnityEngine.Animator, UnityEngine.AnimationModule Data: UnityEngine.Animator, UnityEngine.AnimationModule
@@ -895,7 +949,7 @@ MonoBehaviour:
Data: Data:
- Name: <SystemType>k__BackingField - Name: <SystemType>k__BackingField
Entry: 9 Entry: 9
Data: 45 Data: 48
- 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 +964,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: 49|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: 50|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;
@@ -26,8 +28,10 @@ namespace Marro.PacManUdon
// If user is not owner, this data is read into the same buffer and replayed based on the included timestamp. // If user is not owner, this data is read into the same buffer and replayed based on the included timestamp.
// Data replay is delayed with an offset on the timestamp to hide inconsistency in latency. // Data replay is delayed with an offset on the timestamp to hide inconsistency in latency.
// The timestamp is transferred in ms as a 32 bit uint, which gives a maximum time of about 49 days. // Each event contains a header. The first part contains the size of the event as a ushort, allowing a maximum size of 65,536 bytes.
// The maximum allowed age of a VRChat instance is 7 days, so this should not cause issues. // After that timestamp is transferred in seconds since the owner started the game as a float, matching Unity's time representation.
// Afterwards is a message id, a single byte which increments (with overflow) for every event to confirm data completeness.
// Lastly, a single byte indicates the type of event. 0 is a full sync, which is reserved for syncing up from any unknown state.
// A byte array is used as a DataList or DataDictionary can only be transmitted as JSON which is much less efficient. // A byte array is used as a DataList or DataDictionary can only be transmitted as JSON which is much less efficient.
// As Udon does not support instantiating objects, I have not created classes to represent the data being sent. // As Udon does not support instantiating objects, I have not created classes to represent the data being sent.
@@ -35,7 +39,7 @@ namespace Marro.PacManUdon
// An event has the following structure: // An event has the following structure:
// [0-1]: (ushort) Size of event. // [0-1]: (ushort) Size of event.
// [2-5]: (uint) Time in seconds at which event occured. // [2-5]: (float) Time in seconds at which event occured.
// [6]: (byte) Message id, increments by one for each message with the same timestamp. // [6]: (byte) Message id, increments by one for each message with the same timestamp.
// [7]: (byte) Type of event. 0 = Full Sync, which is used to sync up from an undefinted state. // [7]: (byte) Type of event. 0 = Full Sync, which is used to sync up from an undefinted state.
// [+]: Event-specific data. // [+]: Event-specific data.
@@ -44,11 +48,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,22 +71,10 @@ 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;
/// <summary>
/// The multiplier from Unity time to a timestamp.
/// </summary>
private const int TimestampMultiplier = 1000;
/// <summary>
/// The zero value of a timestamp. Anything below this value is negative.
/// </summary>
private const uint TimestampZeroValue = 1000;
/// <summary> /// <summary>
/// The delay at which the receiving side replays events. /// The delay at which the receiving side replays events.
/// </summary> /// </summary>
@@ -99,16 +87,6 @@ namespace Marro.PacManUdon
/// </summary> /// </summary>
[SerializeField] private SyncedObject[] syncedObjects; [SerializeField] private SyncedObject[] syncedObjects;
/// <summary>
/// Whether the current perspective is the transmitting side.
/// </summary>
private bool isOwner;
/// <summary>
/// Whether the current perspective is synced with the owner. (Always true if current perspective is owner.)
/// </summary>
private bool isSynced;
/// <summary> /// <summary>
/// Offset from system time to network time, including delay. /// Offset from system time to network time, including delay.
/// </summary> /// </summary>
@@ -126,7 +104,7 @@ namespace Marro.PacManUdon
/// <summary> /// <summary>
/// The timestamp of the most recent event created or received. /// The timestamp of the most recent event created or received.
/// </summary> /// </summary>
private uint lastEventTimestamp; private float lastEventTimestamp;
/// <summary> /// <summary>
/// The message id of the most recent event created or received. /// The message id of the most recent event created or received.
/// </summary> /// </summary>
@@ -140,7 +118,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>
@@ -159,6 +137,11 @@ namespace Marro.PacManUdon
/// </summary> /// </summary>
public bool Ready { get; private set; } = false; public bool Ready { get; private set; } = false;
/// <summary>
/// Whether the current perspective is synced with the owner. (Always true if current perspective is owner.)
/// </summary>
public bool Synced { get; private set; } = false;
/// <summary> /// <summary>
/// The time since last full sync which is currently being simulated. /// The time since last full sync which is currently being simulated.
/// </summary> /// </summary>
@@ -179,7 +162,7 @@ namespace Marro.PacManUdon
/// <summary> /// <summary>
/// Is the local user owner? /// Is the local user owner?
/// </summary> /// </summary>
public bool IsOwner => isOwner; public bool IsOwner { get; private set; }
#endregion #endregion
#region General #region General
@@ -193,16 +176,15 @@ namespace Marro.PacManUdon
if (!BitConverter.IsLittleEndian) if (!BitConverter.IsLittleEndian)
{ {
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Fatal: NetworkManager only supports little endian! Network sync will not be possible."); Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Fatal: NetworkManager only supports little endian! Network sync will not be possible.");
var zero = 0; Ready = false;
Debug.Log(1 / zero); // Intentionally crash
return; return;
} }
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 Synced = IsOwner; // Owner is always synced
retriesWithoutSuccess = 0; retriesWithoutSuccess = 0;
lastEventTimestamp = 0; lastEventTimestamp = 0;
lastEventId = 0; lastEventId = 0;
@@ -219,17 +201,20 @@ namespace Marro.PacManUdon
public void FixedUpdate() public void FixedUpdate()
{ {
// Fetch the current time
UpdateInternalTime(); UpdateInternalTime();
if (!isOwner) // If able and needed, process received events
if (Ready && !IsOwner)
{ {
ProgressEventTime(); ProgressEventTime();
} }
// Forwards simulated time at the FixedUpdate pace
PerformFixedSyncedUpdate(); PerformFixedSyncedUpdate();
} }
public void UpdateInternalTime() private void UpdateInternalTime()
{ {
internalTime = Time.fixedTime - offsetTime; internalTime = Time.fixedTime - offsetTime;
} }
@@ -245,23 +230,27 @@ namespace Marro.PacManUdon
} }
} }
private void HandleError() private void HandleError(bool clearBuffer)
{ {
retriesWithoutSuccess++; retriesWithoutSuccess++;
if (retriesWithoutSuccess > 3) if (retriesWithoutSuccess > 3)
{ {
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Fatal: Retried 3 times without success."); Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Fatal: Retried 3 times without success.");
var zero = 0; Ready = false;
Debug.Log(1 / zero); // Intentionally crash
return; return;
} }
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Encountered data error, attempting to recover via full sync."); Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Encountered data error, attempting to recover via full sync.");
ClearBuffer(); if (clearBuffer)
{
ClearBuffer();
}
if (!isOwner) Synced = false;
if (!IsOwner)
{ {
RequestEvent(NetworkEventType.FullSync); RequestEvent(NetworkEventType.FullSync);
} }
@@ -273,7 +262,7 @@ namespace Marro.PacManUdon
private void SetOwner(bool isOwner) private void SetOwner(bool isOwner)
{ {
this.isOwner = isOwner; this.IsOwner = isOwner;
if (DebugImageToIndicateOwner != null) if (DebugImageToIndicateOwner != null)
{ {
@@ -285,59 +274,58 @@ namespace Marro.PacManUdon
#region Sender #region Sender
public void SendEvent(NetworkEventType eventType) public void SendEvent(NetworkEventType eventType)
{ {
if (!isOwner) if (!Ready)
{
return;
}
if (!IsOwner)
{ {
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Attempted {nameof(SendEvent)} while not the owner!"); Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Attempted {nameof(SendEvent)} while not the owner!");
return; return;
} }
var timestamp = TimeToTimestamp(SyncedTime); var timestamp = SyncedTime;
if (timestamp != lastEventTimestamp) var eventId = GetNextEventId(lastEventId);
{
lastEventId = 0;
}
else
{
lastEventId++;
}
var eventId = 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}");
RequestSerialization(); RequestSerialization();
lastEventTimestamp = timestamp;
lastEventId = eventId;
retriesWithoutSuccess = 0; // We had success! retriesWithoutSuccess = 0; // We had success!
} }
private static void InitializeEvent(NetworkEventType eventType, uint timestamp, byte eventId, int maxSize, out byte[][] data, out int index) private static void InitializeEvent(NetworkEventType eventType, float timestamp, byte eventId, int maxSize, out byte[][] data, out int index)
{ {
// Create header // Create header
var timestampBytes = BitConverter.GetBytes(timestamp); var timestampBytes = BitConverter.GetBytes(timestamp);
@@ -347,19 +335,35 @@ 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][];
data[0] = header; data[0] = header;
index = 1; index = 1;
} }
[NetworkCallable]
public void RequestEventReceived(NetworkEventType eventType)
{
if (!Ready)
{
return;
}
SendEvent(eventType);
}
#endregion #endregion
#region Receiver #region Receiver
public void RequestEvent(NetworkEventType eventType) public void RequestEvent(NetworkEventType eventType)
{ {
if (isOwner) if (!Ready)
{
return;
}
if (IsOwner)
{ {
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Attempted {nameof(RequestEvent)} while we are the owner!"); Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Attempted {nameof(RequestEvent)} while we are the owner!");
return; return;
@@ -368,77 +372,109 @@ namespace Marro.PacManUdon
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, "RequestEventReceived", eventType); SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, "RequestEventReceived", eventType);
} }
private void ProcessIncomingData() private void StoreIncomingData()
{ {
if (networkedData.Length == 0) if (networkedData == null || networkedData.Length == 0)
{ {
return; // Nothing to process return; // Nothing to store
} }
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Received {networkedData.Length} bytes!\nBytes received:\n{BytesToString(networkedData)}"); Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Received {networkedData.Length} bytes!\nBytes received:\n{BytesToString(networkedData)}");
var length = networkedData.Length; var length = networkedData.Length;
int index = 0; int index = 0;
while (index < length) int eventSize = 0; // Store event size here so we can increment the index no matter how we increment the loop
while (true)
{ {
index += eventSize;
if (index >= length)
{
break;
}
if (length - index < HeaderLength) if (length - index < HeaderLength)
{ {
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) {nameof(ProcessIncomingData)}: Remaining data in networkedData is not long enough to form a complete event!"); 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(); HandleError(false);
return; return;
} }
var eventSize = networkedData[index + HeaderEventSizeIndex]; eventSize = GetEventSizeFromHeader(networkedData, index);
var eventType = (NetworkEventType)networkedData[index + HeaderEventTypeIndex];
if (length - index < eventSize)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) {nameof(StoreIncomingData)}: Event size is larger than total remaining data! {nameof(eventSize)}: {eventSize}, remaining: {length - index}.");
HandleError(false);
return;
}
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
index += eventSize;
continue; continue;
} }
if (!isSynced) if (!Synced)
{ {
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Received event of type {eventType} while we are not yet synced to the remote time, ignoring event."); Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Received event of type {eventType} while we are not yet synced to the remote time, ignoring event.");
index += eventSize;
continue; continue;
} }
var timestamp = networkedData[index + HeaderTimestampIndex]; var timestamp = GetTimestampFromHeader(@event);
var messageId = networkedData[index + HeaderEventIdIndex]; var eventId = GetEventIdFromHeader(@event);
if (timestamp == lastEventTimestamp if (timestamp == lastEventTimestamp
&& messageId == lastEventId) && eventId == lastEventId)
{ {
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Duplicate message of type {eventType}, timestamp: {timestamp}, messageId: {messageId}."); Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Duplicate message of type {eventType}, timestamp: {timestamp}, messageId: {eventId}.");
index += eventSize;
continue; continue;
} }
AppendEventToBuffer(index, eventSize); if (eventId != GetNextEventId(lastEventId))
index += eventSize; {
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) EventIds were not sequential! Did we miss a serialization? Timestamp: {timestamp}, eventId: {eventId}, lastEventId: {lastEventId}.");
HandleError(false);
return;
}
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 // 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
UpdateNextEventTime(ignoreOrder: true); UpdateNextEventTime(ignoreOrder: true);
isSynced = true; Synced = true;
} }
private void ProgressEventTime() private void ProgressEventTime()
@@ -454,11 +490,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)
{ {
@@ -467,32 +505,25 @@ 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)
{ {
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Malformed data reported by {obj.name} during event type {eventType}!"); Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Malformed data reported by {obj.name} during event type {eventType}!");
HandleError(); 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();
return; 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}.");
HandleError(); HandleError(true);
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.");
@@ -503,7 +534,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;
} }
@@ -511,69 +542,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(); // We can store event now that we cleared the buffer.
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
@@ -590,10 +578,10 @@ namespace Marro.PacManUdon
SyncedTime = newTime; SyncedTime = newTime;
} }
private void SyncToTimestamp(uint timestamp, byte eventId) private void SyncToTimestamp(float timestamp, byte eventId)
{ {
var oldOffset = offsetTime; var oldOffset = offsetTime;
var timeToSyncTo = TimestampToTime(timestamp) - Delay; var timeToSyncTo = timestamp - Delay;
offsetTime = Time.fixedTime - timeToSyncTo; offsetTime = Time.fixedTime - timeToSyncTo;
var delta = offsetTime - oldOffset; var delta = offsetTime - oldOffset;
@@ -613,7 +601,7 @@ namespace Marro.PacManUdon
return; return;
} }
var nextEventTime = TimestampToTime(BitConverter.ToUInt32(buffer, HeaderTimestampIndex)); var nextEventTime = GetTimestampFromHeader(NextEvent);
if (ignoreOrder || nextEventTime >= this.nextEventTime) if (ignoreOrder || nextEventTime >= this.nextEventTime)
{ {
this.nextEventTime = nextEventTime; this.nextEventTime = nextEventTime;
@@ -621,39 +609,67 @@ namespace Marro.PacManUdon
else else
{ {
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) New event is earlier than previous event!"); Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) New event is earlier than previous event!");
HandleError(); HandleError(true);
return; return;
} }
} }
#endregion
public static uint TimeToTimestamp(float time) #region Header
private static byte GetNextEventId(byte currentEventId)
{ {
return (uint)((time * TimestampMultiplier) + TimestampZeroValue); if (currentEventId == byte.MaxValue) // Udon forces overflow checks
{
return 0;
}
currentEventId += 1;
return currentEventId;
} }
public static float TimestampToTime(uint timeStamp) private static ushort GetEventSizeFromHeader(byte[] @event, int eventIndex = 0)
{ => BitConverter.ToUInt16(@event, eventIndex + HeaderEventSizeIndex);
return (timeStamp - (long)TimestampZeroValue) / (float)TimestampMultiplier; // Use a long here to prevent an underflow
} private static NetworkEventType GetEventTypeFromHeader(byte[] @event, int eventIndex = 0) =>
(NetworkEventType)@event[eventIndex + HeaderEventTypeIndex];
private static float GetTimestampFromHeader(byte[] @event, int eventIndex = 0) =>
BitConverter.ToSingle(@event, eventIndex + HeaderTimestampIndex);
private static byte GetEventIdFromHeader(byte[] @event, int eventIndex = 0) =>
@event[eventIndex + HeaderEventIdIndex];
#endregion #endregion
#region VRC events #region VRC events
public override void OnOwnershipTransferred(VRCPlayerApi newOwner) public override void OnOwnershipTransferred(VRCPlayerApi newOwner)
{ {
SetOwner(newOwner == Networking.LocalPlayer); if (!Ready)
if(isOwner)
{ {
HandleError(); return;
} }
SetOwner(newOwner == Networking.LocalPlayer);
} }
private int indexAtLastSerialization = 0;
public override void OnPreSerialization() public override void OnPreSerialization()
{ {
if (isOwner) if (!Ready)
{ {
networkedData = new byte[bufferIndex]; return;
Array.Copy(buffer, networkedData, bufferIndex); }
if (IsOwner)
{
if (buffer == null || bufferIndex == 0)
{
return;
}
networkedData = Flatten(buffer, 0, bufferIndex);
indexAtLastSerialization = bufferIndex;
} }
else else
{ {
@@ -663,13 +679,18 @@ 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.");
return; return;
} }
if (!isOwner || networkedData.Length == 0) if (!IsOwner || networkedData.Length == 0)
{ {
return; return;
} }
@@ -677,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)
{ {
ProcessIncomingData(); return;
} }
StoreIncomingData();
} }
#endregion #endregion
@@ -702,19 +725,46 @@ 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
public void SimulateSyncToTimestamp(uint timestamp) public void SimulateSyncToTimestamp(float timestamp)
{ {
SyncToTimestamp(timestamp, 0); SyncToTimestamp(timestamp, 0);
} }
@@ -722,7 +772,8 @@ namespace Marro.PacManUdon
public void WriteDebugOutput(TMP_InputField debugOutput) public void WriteDebugOutput(TMP_InputField debugOutput)
{ {
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" +

View File

@@ -400,10 +400,10 @@ MonoBehaviour:
Data: loopOffset Data: loopOffset
- Name: <UserType>k__BackingField - Name: <UserType>k__BackingField
Entry: 9 Entry: 9
Data: 11 Data: 19
- Name: <SystemType>k__BackingField - Name: <SystemType>k__BackingField
Entry: 9 Entry: 9
Data: 11 Data: 19
- 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

View File

@@ -24,15 +24,15 @@ public class TestBall : SyncedObject
private NetworkManager networkManager; private NetworkManager networkManager;
private const int LoopTimeMs = 1000; private const float LoopTime = 1f;
private const float MaxUp = 0.7f; private const float MaxUp = 0.7f;
private const float UpPerPress = 0.4f; private const float UpPerPress = 0.4f;
private const float DownPerSecond = 1; private const float DownPerSecond = 1f;
private float sumOfDt; private float sumOfDt;
private float amountUp = 0; private float amountUp = 0;
private int loopOffset = 0; private float loopOffset = 0;
private float[] jumps; private float[] jumps;
private int jumpsIndex; private int jumpsIndex;
@@ -78,25 +78,25 @@ public class TestBall : SyncedObject
private void SetProgress(float progress) private void SetProgress(float progress)
{ {
var currentTimestamp = GetCurrentTimestamp(); var currentTimestamp = GetCurrentTimestamp();
loopOffset = (int)(currentTimestamp - progress * LoopTimeMs); loopOffset = (currentTimestamp - progress) * LoopTime;
} }
private float GetProgress() private float GetProgress()
{ {
var currentTimestamp = GetCurrentTimestamp(); var currentTimestamp = GetCurrentTimestamp();
//Debug.Log($"CurrentTimeStamp for mode {mode}: {currentTimestamp}"); //Debug.Log($"CurrentTimeStamp for mode {mode}: {currentTimestamp}");
return ((int)currentTimestamp - loopOffset) % LoopTimeMs / (float)LoopTimeMs; // "uint % int" is not exposed, I love working in Udon return (currentTimestamp - loopOffset) % LoopTime / LoopTime;
} }
private uint GetCurrentTimestamp() private float GetCurrentTimestamp()
{ {
switch (mode) switch (mode)
{ {
case TestBallMode.UseNetworkTime: case TestBallMode.UseNetworkTime:
return NetworkManager.TimeToTimestamp(networkManager.SyncedTime); return networkManager.SyncedTime;
case TestBallMode.UseNetworkDt: case TestBallMode.UseNetworkDt:
case TestBallMode.UseUnityDt: case TestBallMode.UseUnityDt:
return NetworkManager.TimeToTimestamp(sumOfDt); return sumOfDt;
default: default:
Debug.LogError($"({nameof(TestBall)}) Unknown mode {mode}!"); Debug.LogError($"({nameof(TestBall)}) Unknown mode {mode}!");
return 0; return 0;

View File

@@ -56,11 +56,15 @@ public class TestBallManager : UdonSharpBehaviour
{ {
if (VRCPlayerApi.GetPlayerCount() == 1) if (VRCPlayerApi.GetPlayerCount() == 1)
{ {
networkManager.SimulateSyncToTimestamp(NetworkManager.TimeToTimestamp(networkManager.SyncedTime - 0.5f)); networkManager.SimulateSyncToTimestamp(networkManager.SyncedTime - 0.5f);
}
else if (networkManager.IsOwner)
{
networkManager.SendEvent(NetworkEventType.FullSync);
} }
else else
{ {
networkManager.SendEvent((NetworkEventType)0); networkManager.RequestEvent(NetworkEventType.FullSync);
} }
} }
} }