From 74223c8139dde441ece8d910cd6d322e9b81d968 Mon Sep 17 00:00:00 2001 From: Marro64 Date: Sun, 28 Dec 2025 19:35:18 +0100 Subject: [PATCH] Added NetworkManager --- .vsconfig | 6 + Assets/Scenes/PacMan.unity | 85 +++ Assets/Scripts/GameManager.cs | 31 +- Assets/Scripts/Ghost.cs | 34 +- Assets/Scripts/GridMover.cs | 42 +- Assets/Scripts/GridMoverTools.cs | 6 - Assets/Scripts/NetworkManager.asset | 442 ++++++++++++++ Assets/Scripts/NetworkManager.asset.meta | 8 + Assets/Scripts/NetworkManager.cs | 283 +++++++++ Assets/Scripts/NetworkManager.cs.meta | 11 + Assets/Scripts/PacMan.asset | 548 +++++++++--------- Assets/Scripts/PacMan.cs | 24 +- Assets/Scripts/PlayerInput.cs | 11 +- .../Scripts/Sequences/TimeSequenceShared.cs | 37 +- Assets/Scripts/SyncedObject.cs | 12 + Assets/Scripts/SyncedObject.cs.meta | 11 + 16 files changed, 1224 insertions(+), 367 deletions(-) create mode 100644 .vsconfig create mode 100644 Assets/Scripts/NetworkManager.asset create mode 100644 Assets/Scripts/NetworkManager.asset.meta create mode 100644 Assets/Scripts/NetworkManager.cs create mode 100644 Assets/Scripts/NetworkManager.cs.meta create mode 100644 Assets/Scripts/SyncedObject.cs create mode 100644 Assets/Scripts/SyncedObject.cs.meta diff --git a/.vsconfig b/.vsconfig new file mode 100644 index 0000000..f019fd0 --- /dev/null +++ b/.vsconfig @@ -0,0 +1,6 @@ +{ + "version": "1.0", + "components": [ + "Microsoft.VisualStudio.Workload.ManagedGame" + ] +} diff --git a/Assets/Scenes/PacMan.unity b/Assets/Scenes/PacMan.unity index 98274c4..8672511 100644 --- a/Assets/Scenes/PacMan.unity +++ b/Assets/Scenes/PacMan.unity @@ -24286,6 +24286,86 @@ Transform: - {fileID: 653732755} m_Father: {fileID: 2146786255} m_LocalEulerAnglesHint: {x: -86.927, y: 56.585, z: 0} +--- !u!1 &811840790 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 811840791} + - component: {fileID: 811840793} + - component: {fileID: 811840792} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &811840791 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 811840790} + 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: 1170168279} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &811840792 +MonoBehaviour: + m_ObjectHideFlags: 2 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 811840790} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 45115577ef41a5b4ca741ed302693907, type: 3} + m_Name: + m_EditorClassIdentifier: + interactTextPlacement: {fileID: 0} + interactText: Use + interactTextGO: {fileID: 0} + proximity: 2 + SynchronizePosition: 0 + AllowCollisionOwnershipTransfer: 0 + Reliable: 0 + _syncMethod: 3 + serializedProgramAsset: {fileID: 11400000, guid: 37b60ab207700554ba5c119f63c3c7bd, type: 2} + programSource: {fileID: 11400000, guid: a327a0e472dbf694a8e2b23bf0ce90d0, type: 2} + serializedPublicVariablesBytesString: Ai8AAAAAATIAAABWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgAuAFUAZABvAG4AVgBhAHIAaQBhAGIAbABlAFQAYQBiAGwAZQAsACAAVgBSAEMALgBVAGQAbwBuAC4AQwBvAG0AbQBvAG4AAAAAAAYBAAAAAAAAACcBBAAAAHQAeQBwAGUAAWgAAABTAHkAcwB0AGUAbQAuAEMAbwBsAGwAZQBjAHQAaQBvAG4AcwAuAEcAZQBuAGUAcgBpAGMALgBMAGkAcwB0AGAAMQBbAFsAVgBSAEMALgBVAGQAbwBuAC4AQwBvAG0AbQBvAG4ALgBJAG4AdABlAHIAZgBhAGMAZQBzAC4ASQBVAGQAbwBuAFYAYQByAGkAYQBiAGwAZQAsACAAVgBSAEMALgBVAGQAbwBuAC4AQwBvAG0AbQBvAG4AXQBdACwAIABtAHMAYwBvAHIAbABpAGIAAQEJAAAAVgBhAHIAaQBhAGIAbABlAHMALwEAAAABaAAAAFMAeQBzAHQAZQBtAC4AQwBvAGwAbABlAGMAdABpAG8AbgBzAC4ARwBlAG4AZQByAGkAYwAuAEwAaQBzAHQAYAAxAFsAWwBWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgAuAEkAbgB0AGUAcgBmAGEAYwBlAHMALgBJAFUAZABvAG4AVgBhAHIAaQBhAGIAbABlACwAIABWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgBdAF0ALAAgAG0AcwBjAG8AcgBsAGkAYgABAAAABgEAAAAAAAAAAi8CAAAAAUkAAABWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgAuAFUAZABvAG4AVgBhAHIAaQBhAGIAbABlAGAAMQBbAFsAUwB5AHMAdABlAG0ALgBJAG4AdAAzADIALAAgAG0AcwBjAG8AcgBsAGkAYgBdAF0ALAAgAFYAUgBDAC4AVQBkAG8AbgAuAEMAbwBtAG0AbwBuAAIAAAAGAgAAAAAAAAAnAQQAAAB0AHkAcABlAAEXAAAAUwB5AHMAdABlAG0ALgBTAHQAcgBpAG4AZwAsACAAbQBzAGMAbwByAGwAaQBiACcBCgAAAFMAeQBtAGIAbwBsAE4AYQBtAGUAAR8AAABfAF8AXwBVAGQAbwBuAFMAaABhAHIAcABCAGUAaABhAHYAaQBvAHUAcgBWAGUAcgBzAGkAbwBuAF8AXwBfACcBBAAAAHQAeQBwAGUAARYAAABTAHkAcwB0AGUAbQAuAEkAbgB0ADMAMgAsACAAbQBzAGMAbwByAGwAaQBiABcBBQAAAFYAYQBsAHUAZQACAAAABwUHBQcF + publicVariablesUnityEngineObjects: [] + publicVariablesSerializationDataFormat: 0 +--- !u!114 &811840793 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 811840790} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac984c07ae3e9674a850c3916be56ca3, type: 3} + m_Name: + m_EditorClassIdentifier: + serializationData: + SerializedFormat: 2 + SerializedBytes: + ReferencedUnityObjects: [] + SerializedBytesString: + Prefab: {fileID: 0} + PrefabModificationsReferencedUnityObjects: [] + PrefabModifications: [] + SerializationNodes: [] + _udonSharpBackingUdonBehaviour: {fileID: 811840792} --- !u!1 &817541382 stripped GameObject: m_CorrespondingSourceObject: {fileID: 4099390335584803315, guid: 00a825a5aeafee94789192f61cbb3a5a, type: 3} @@ -35201,6 +35281,7 @@ Transform: - {fileID: 151056553} - {fileID: 934262201} - {fileID: 723443144} + - {fileID: 811840791} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1001 &1173475478 @@ -52835,6 +52916,10 @@ MonoBehaviour: ID: 302 SerializedTypeNames: - VRC.Udon.UdonBehaviour + - gameObject: {fileID: 811840790} + ID: 303 + SerializedTypeNames: + - VRC.Udon.UdonBehaviour portraitCameraPositionOffset: {x: 0, y: 0, z: 0} portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} PlayerPersistence: [] diff --git a/Assets/Scripts/GameManager.cs b/Assets/Scripts/GameManager.cs index 57c7f71..d2aa6c6 100644 --- a/Assets/Scripts/GameManager.cs +++ b/Assets/Scripts/GameManager.cs @@ -2,16 +2,14 @@ namespace Marro.PacManUdon { + using Assets.Scripts; using System; using UdonSharp; using UnityEngine; - using VRC.SDKBase; - using VRC.Udon; using VRC.SDK3.Components; - using VRC.Udon.Common.Interfaces; - using VRC.SDK3.Data; + using VRC.SDKBase; - public partial class GameManager : UdonSharpBehaviour + public partial class GameManager : SyncedObject { [Header("Static game components")] [SerializeField] private Maze[] mazes; @@ -26,6 +24,7 @@ namespace Marro.PacManUdon [SerializeField] private PlayerInput playerInput; [SerializeField] private Animator demo; [SerializeField] private SoundManager soundManager; + [SerializeField] private NetworkManager networkManager; [SerializeField] private GameObject recorder; @@ -79,6 +78,7 @@ namespace Marro.PacManUdon playerInput.Initialize(this); soundManager.Initialize(); intermission2Pole.Initialize(this, ghostManager.Ghosts[0]); + networkManager.Initialize(Networking.IsOwner(gameObject)); HideEverything(); @@ -445,6 +445,27 @@ namespace Marro.PacManUdon ghostManager.SetOwner(Networking.LocalPlayer); } + public override void AppendSyncedData(byte[][] data, ref int offset) + { + data[offset++] = new byte[] { (byte)gameState }; + data[offset++] = BitConverter.GetBytes(currentlyInTimeSequence); + data[offset++] = new byte[] { (byte) currentTimeSequence }; + data[offset++] = BitConverter.GetBytes(timeSequenceProgress); + } + + public override bool SetSyncedData(byte[] data, ref int offset) + { + SetGameState((PacManGameState)data[offset++]); + + var currentlyInTimeSequence = BitConverter.ToBoolean(data, offset++); + var currentTimeSequence = (PacManTimeSequence)data[offset++]; + var timeSequenceProgress = BitConverter.ToSingle(data, offset); + offset += 4; + TimeSequenceSyncWithRemote(currentlyInTimeSequence, currentTimeSequence, timeSequenceProgress); + + return true; + } + public int ExtraLives { set diff --git a/Assets/Scripts/Ghost.cs b/Assets/Scripts/Ghost.cs index a3f5c35..0b1a31b 100644 --- a/Assets/Scripts/Ghost.cs +++ b/Assets/Scripts/Ghost.cs @@ -478,7 +478,7 @@ namespace Marro.PacManUdon } } - private void UpdateAnimator() + protected override void UpdateAnimator() { if (!gameObject.activeInHierarchy) return; @@ -783,43 +783,15 @@ namespace Marro.PacManUdon public bool IsScared => isScared; - public override Vector2 GetPosition() - { - return (Vector2)transform.localPosition; - } - - public override void SetPosition(Vector2 position) - { - GridMoverTools.SetPosition(position, transform); - } - - public override Vector2 GetDirection() - { - return direction; - } - - public void SetDirection(Vector2 direction) - { - this.direction = direction; - UpdateAnimator(); - RequestSerialization(); - } - public void SetSpeed(float speed) { this.speed = speed; UpdateAnimator(); } - public override void OnPreSerialization() + public override void AppendSyncedData(byte[][] data, ref int offset) { - syncedPosition = GetPosition(); - } - - public override void OnDeserialization() - { - SetPosition(syncedPosition); - UpdateAnimator(); + base.AppendSyncedData(data, ref offset); } void OnTriggerEnter(Collider other) diff --git a/Assets/Scripts/GridMover.cs b/Assets/Scripts/GridMover.cs index 8924c01..fed7d08 100644 --- a/Assets/Scripts/GridMover.cs +++ b/Assets/Scripts/GridMover.cs @@ -1,26 +1,56 @@ namespace Marro.PacManUdon { + using Assets.Scripts; using System; using UdonSharp; using UnityEngine; + using VRC.Udon.Serialization.OdinSerializer; - public abstract class GridMover : UdonSharpBehaviour + public abstract class GridMover : SyncedObject { + protected Vector2 direction; + public virtual Vector2 GetPosition() { - Debug.LogError($"{gameObject} does not implement GetPosition"); - return Vector2.zero; + return (Vector2)transform.localPosition; } public virtual void SetPosition(Vector2 position) { - Debug.LogError($"{gameObject} does not implement SetPosition"); + transform.localPosition = new Vector3(position.x, position.y, transform.localPosition.z); } public virtual Vector2 GetDirection() { - Debug.LogError($"{gameObject} does not implement GetDirection"); - return Vector2.zero; + return direction; + } + + public void SetDirection(Vector2 direction) + { + this.direction = direction; + UpdateAnimator(); + } + + protected abstract void UpdateAnimator(); + + public override void AppendSyncedData(byte[][] data, ref int offset) + { + var position = GetPosition(); + data[offset++] = BitConverter.GetBytes(position.x); + data[offset++] = BitConverter.GetBytes(position.y); + + var direction = GetDirection(); + data[offset++] = BitConverter.GetBytes(direction.x); + data[offset++] = BitConverter.GetBytes(direction.y); + } + + public override bool SetSyncedData(byte[] data, ref int offset) + { + SetPosition(new Vector2(BitConverter.ToSingle(data, offset), BitConverter.ToSingle(data, offset + 2))); + SetDirection(new Vector2(BitConverter.ToSingle(data, offset + 4), BitConverter.ToSingle(data, offset + 6))); + offset += 8; + + return true; } } } \ No newline at end of file diff --git a/Assets/Scripts/GridMoverTools.cs b/Assets/Scripts/GridMoverTools.cs index 50901df..2dfdfd8 100644 --- a/Assets/Scripts/GridMoverTools.cs +++ b/Assets/Scripts/GridMoverTools.cs @@ -10,12 +10,6 @@ namespace Marro.PacManUdon return currentPosition + direction * speed * Time.deltaTime; } - public static void SetPosition(Vector2 position, Transform transform) - { - transform.localPosition = new Vector3(position.x, position.y, transform.localPosition.z); - } - - public static Vector2 PositionToGrid(Vector2 position) { return new Vector2((float)Math.Round(position.x), (float)Math.Round(position.y)); diff --git a/Assets/Scripts/NetworkManager.asset b/Assets/Scripts/NetworkManager.asset new file mode 100644 index 0000000..ec64ef7 --- /dev/null +++ b/Assets/Scripts/NetworkManager.asset @@ -0,0 +1,442 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c333ccfdd0cbdbc4ca30cef2dd6e6b9b, type: 3} + m_Name: NetworkManager + m_EditorClassIdentifier: + serializedUdonProgramAsset: {fileID: 11400000, guid: 37b60ab207700554ba5c119f63c3c7bd, type: 2} + udonAssembly: + assemblyError: + sourceCsScript: {fileID: 11500000, guid: ac984c07ae3e9674a850c3916be56ca3, type: 3} + scriptVersion: 2 + compiledVersion: 2 + behaviourSyncMode: 0 + hasInteractEvent: 0 + scriptID: -3442137929426346155 + serializationData: + SerializedFormat: 2 + SerializedBytes: + ReferencedUnityObjects: [] + SerializedBytesString: + Prefab: {fileID: 0} + PrefabModificationsReferencedUnityObjects: [] + PrefabModifications: [] + SerializationNodes: + - Name: fieldDefinitions + Entry: 7 + Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[UdonSharp.Compiler.FieldDefinition, + UdonSharp.Editor]], mscorlib + - Name: comparer + Entry: 7 + Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.String, + mscorlib]], mscorlib + - Name: + Entry: 8 + Data: + - Name: + Entry: 12 + Data: 7 + - Name: + Entry: 7 + Data: + - Name: $k + Entry: 1 + Data: syncedObjects + - Name: $v + Entry: 7 + Data: 2|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: syncedObjects + - Name: k__BackingField + Entry: 7 + Data: 3|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: Assets.Scripts.SyncedObject[], Assembly-CSharp + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 7 + Data: 4|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: UnityEngine.Component[], UnityEngine.CoreModule + - 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: true + - Name: _fieldAttributes + Entry: 7 + Data: 5|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 1 + - Name: + Entry: 7 + Data: 6|UnityEngine.SerializeField, UnityEngine.CoreModule + - Name: + Entry: 8 + Data: + - 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 + - Name: $v + Entry: 7 + Data: 7|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: isOwner + - Name: k__BackingField + Entry: 7 + Data: 8|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Boolean, mscorlib + - Name: + Entry: 8 + Data: + - 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: 9|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: startTimeTicks + - Name: $v + Entry: 7 + Data: 10|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: startTimeTicks + - Name: k__BackingField + Entry: 7 + Data: 11|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Int64, mscorlib + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 9 + Data: 11 + - 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: 12|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: nextEventTime + - Name: $v + Entry: 7 + Data: 13|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: nextEventTime + - Name: k__BackingField + Entry: 7 + Data: 14|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.UInt32, mscorlib + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 9 + Data: 14 + - 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: 15|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: buffer + - Name: $v + Entry: 7 + Data: 16|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: buffer + - Name: k__BackingField + Entry: 7 + Data: 17|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Byte[], mscorlib + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 9 + Data: 17 + - 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: 18|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: index + - Name: $v + Entry: 7 + Data: 19|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: index + - Name: k__BackingField + Entry: 7 + Data: 20|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Int32, mscorlib + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 9 + Data: 20 + - 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: 21|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: 22|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: networkedData + - Name: k__BackingField + Entry: 9 + Data: 17 + - Name: k__BackingField + Entry: 9 + Data: 17 + - Name: k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 3 + Data: 1 + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 23|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 1 + - Name: + Entry: 7 + Data: 24|UdonSharp.UdonSyncedAttribute, UdonSharp.Runtime + - Name: + Entry: 8 + Data: + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: diff --git a/Assets/Scripts/NetworkManager.asset.meta b/Assets/Scripts/NetworkManager.asset.meta new file mode 100644 index 0000000..a25594f --- /dev/null +++ b/Assets/Scripts/NetworkManager.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a327a0e472dbf694a8e2b23bf0ce90d0 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/NetworkManager.cs b/Assets/Scripts/NetworkManager.cs new file mode 100644 index 0000000..9d0509e --- /dev/null +++ b/Assets/Scripts/NetworkManager.cs @@ -0,0 +1,283 @@ +using Assets.Scripts; +using JetBrains.Annotations; +using System; +using System.Text; +using UdonSharp; +using UnityEngine; +using UnityEngine.UIElements; +using VRC.SDK3.Data; +using VRC.SDK3.UdonNetworkCalling; +using VRC.Udon.Common; +using static VRC.SDKBase.Networking; + +namespace Marro.PacManUdon +{ + enum NetworkEventType + { + FullSync = 0, + } + public class NetworkManager : UdonSharpBehaviour + { + // The network manager works by serializing event and state data into a byte array, including a timestamp for each event. + // If user is owner, this data is created and stored in a buffer which is cleared upon transmission. + // 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. + + // The timestamp is transferred in ms as a 32 bit uint, which gives a maximum time of about 49 days. + // The maximum allowed age of a VRChat instance is 7 days, so this should not cause issues. + + // 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. + // Correct parsing is dependend upon everything being read out identially to how it was created. + + // An event has the following structure: + // [0-3]: (uint) Time in seconds at which event occured. + // [4]: (byte) Type of event: 0 = Full Sync, others will be defined later. + // [5+]: Event-specific data + + const int BufferSizeBytes = 1000; + + [SerializeField] + private SyncedObject[] syncedObjects; + + private bool isOwner; + + private long startTimeTicks; + + private uint nextEventTime; + + // Main buffer of events + private byte[] buffer; + private int index; + + [UdonSynced] private byte[] networkedData; + + public void Initialize(bool isOwner) + { + buffer = new byte[BufferSizeBytes]; + index = 0; + startTimeTicks = DateTime.UtcNow.Ticks; + this.isOwner = isOwner; + } + + public void Update() + { + if (!isOwner) + { + ProgressReplayTime(); + } + } + + [NetworkCallable] + public void DoFullSync() + { + if (!isOwner) + { + Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Attempted {nameof(DoFullSync)} while not the owner!"); + return; + } + + InitializeEvent(NetworkEventType.FullSync, 1000, out byte[][] data, out var index); + + foreach (var obj in syncedObjects) + { + obj.AppendSyncedData(data, ref index); + } + + FlattenAndCopy(data, buffer, ref index); + + RequestSerialization(); + } + + public void RequestFullSync() + { + if (isOwner) + { + Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Attempted {nameof(RequestFullSync)} while we are the owner!"); + return; + } + + SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, "DoFullSync"); + } + + private void ProcessIncomingData() + { + var syncType = (NetworkEventType)networkedData[4]; + var size = networkedData.Length; + + if (!EnsureSpaceToStoreEvent(size, syncType == NetworkEventType.FullSync)) + { + return; + } + + Array.Copy(networkedData, 0, buffer, index, size); + index += size; + + UpdateNextEventTime(); + } + + private void ProgressReplayTime() + { + var currentTime = CurrentTime; + while (index != 0 && nextEventTime <= currentTime) + { + ProcessNextEvent(); + UpdateNextEventTime(); + } + } + + private void UpdateNextEventTime() + { + if (index > 0) + { + var nextEventTime = BitConverter.ToUInt32(buffer, 0); + if (nextEventTime >= this.nextEventTime) + { + this.nextEventTime = nextEventTime; + } + else + { + Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Events are in invalid order! Clearing buffer."); + ClearBuffer(); + return; + } + } + } + + private void ProcessNextEvent() + { + var eventType = (NetworkEventType)buffer[4]; + + switch (eventType) + { + default: + Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Invalid sync type for incoming data! Buffer will be cleared."); + ClearBuffer(); + return; + case NetworkEventType.FullSync: + ProcessFullSync(); + return; + } + } + + private void ProcessFullSync() + { + var index = 0; + foreach (var obj in syncedObjects) + { + var success = obj.SetSyncedData(buffer, ref index); + + if (!success) + { + Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Malformed data reported by {obj.name} during full sync! Clearing buffer and requesting new full sync."); + ClearBuffer(); + RequestFullSync(); + return; + } + } + + RemoveProcessedDataFromBuffer(index); + + Debug.Log($"Processed full sync! Total {index} bytes."); + } + + private bool EnsureSpaceToStoreEvent(int eventSize, bool isFullSync) + { + if (index + eventSize <= buffer.Length) + { + return true; // Enough space! + } + + if (isFullSync && index == 0) + { + Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Buffer is not large enough to store full sync! Viewing remote play is not possible."); + return false; // Unable to store full sync, networking features will not function. + } + + ClearBuffer(); + + if (!isFullSync) + { + Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Too much data in buffer to store event! Old events will be discarded, and full sync will be performed."); + + RequestFullSync(); + + return false; // No use storing this event, we're going to wait for the full sync. + } + + Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Too much data in buffer to store full sync! Old events will be discarded."); + return true; // We can store event now that we cleared the buffer. + } + + private void InitializeEvent(NetworkEventType eventType, int maxSize, out byte[][] data, out int index) + { + data = new byte[maxSize][]; + index = 2; + + data[0] = BitConverter.GetBytes(CurrentTime); + data[1] = new byte[] { (byte)eventType }; + } + + private void FlattenAndCopy(byte[][] data, byte[] target, ref int index) + { + foreach (byte[] values in data) + { + Array.Copy(values, 0, target, index, values.Length); + index += values.Length; + } + } + + private void RemoveProcessedDataFromBuffer(int amountProcessed) + { + var oldBuffer = buffer; + index -= amountProcessed; + buffer = new byte[BufferSizeBytes]; + Array.Copy(oldBuffer, amountProcessed, buffer, 0, index); + } + + private void ClearBuffer() + { + buffer = new byte[BufferSizeBytes]; + index = 0; + } + + public override void OnPreSerialization() + { + if (isOwner) + { + networkedData = new byte[index]; + Array.Copy(buffer, networkedData, index); + } + } + + public override void OnPostSerialization(SerializationResult result) + { + if (!result.success) + { + Debug.LogWarning($"Serialization failed! Tried to send {result.byteCount} bytes."); + return; + } + + Debug.Log($"Serialized with {result.byteCount} bytes!"); + + if (isOwner) + { + // Remove all transferred data from the buffer, leaving data that came in after serialization + RemoveProcessedDataFromBuffer(networkedData.Length); + networkedData = null; + } + } + + public override void OnDeserialization() + { + if (!isOwner) + { + ProcessIncomingData(); + } + } + + public uint CurrentTime => (uint)((DateTime.UtcNow.Ticks - startTimeTicks) / TimeSpan.TicksPerMillisecond); + + public bool IsOwner => isOwner; + } +} diff --git a/Assets/Scripts/NetworkManager.cs.meta b/Assets/Scripts/NetworkManager.cs.meta new file mode 100644 index 0000000..4ec3c08 --- /dev/null +++ b/Assets/Scripts/NetworkManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac984c07ae3e9674a850c3916be56ca3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PacMan.asset b/Assets/Scripts/PacMan.asset index 4564171..2917ba8 100644 --- a/Assets/Scripts/PacMan.asset +++ b/Assets/Scripts/PacMan.asset @@ -49,31 +49,25 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: gameController + Data: direction - Name: $v Entry: 7 Data: 2|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: gameController + Data: direction - Name: k__BackingField Entry: 7 Data: 3|System.RuntimeType, mscorlib - Name: Entry: 1 - Data: Marro.PacManUdon.GameManager, Assembly-CSharp + Data: UnityEngine.Vector2, UnityEngine.CoreModule - Name: Entry: 8 Data: - Name: k__BackingField - Entry: 7 - Data: 4|System.RuntimeType, mscorlib - - Name: - Entry: 1 - Data: VRC.Udon.UdonBehaviour, VRC.Udon - - Name: - Entry: 8 - Data: + Entry: 9 + Data: 3 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -88,7 +82,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 5|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 4|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -109,25 +103,31 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: input + Data: gameController - Name: $v Entry: 7 - Data: 6|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 5|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: input + Data: gameController - Name: k__BackingField Entry: 7 - Data: 7|System.RuntimeType, mscorlib + Data: 6|System.RuntimeType, mscorlib - Name: Entry: 1 - Data: Marro.PacManUdon.PlayerInput, Assembly-CSharp + Data: Marro.PacManUdon.GameManager, Assembly-CSharp - Name: Entry: 8 Data: - Name: k__BackingField - Entry: 9 - Data: 4 + Entry: 7 + Data: 7|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: VRC.Udon.UdonBehaviour, VRC.Udon + - Name: + Entry: 8 + Data: - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -163,25 +163,25 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: defaultSpeed + Data: input - Name: $v Entry: 7 Data: 9|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: defaultSpeed + Data: input - Name: k__BackingField Entry: 7 Data: 10|System.RuntimeType, mscorlib - Name: Entry: 1 - Data: System.Single, mscorlib + Data: Marro.PacManUdon.PlayerInput, Assembly-CSharp - Name: Entry: 8 Data: - Name: k__BackingField Entry: 9 - Data: 10 + Data: 7 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -217,19 +217,73 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: powerPelletSpeed + Data: defaultSpeed - Name: $v Entry: 7 Data: 12|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: defaultSpeed + - Name: k__BackingField + Entry: 7 + Data: 13|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Single, mscorlib + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 9 + Data: 13 + - 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: 14|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: powerPelletSpeed + - Name: $v + Entry: 7 + Data: 15|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: powerPelletSpeed - Name: k__BackingField Entry: 9 - Data: 10 + Data: 13 - Name: k__BackingField Entry: 9 - Data: 10 + Data: 13 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -244,7 +298,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 13|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 16|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -268,70 +322,16 @@ MonoBehaviour: Data: speed - Name: $v Entry: 7 - Data: 14|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 17|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: speed - Name: k__BackingField Entry: 9 - Data: 10 + Data: 13 - Name: k__BackingField Entry: 9 - Data: 10 - - 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: 15|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: startPosition - - Name: $v - Entry: 7 - Data: 16|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - - Name: k__BackingField - Entry: 1 - Data: startPosition - - Name: k__BackingField - Entry: 7 - Data: 17|System.RuntimeType, mscorlib - - Name: - Entry: 1 - Data: UnityEngine.Vector3, UnityEngine.CoreModule - - Name: - Entry: 8 - Data: - - Name: k__BackingField - Entry: 9 - Data: 17 + Data: 13 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -367,19 +367,19 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: startRotation + Data: startPosition - Name: $v Entry: 7 Data: 19|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: startRotation + Data: startPosition - Name: k__BackingField Entry: 7 Data: 20|System.RuntimeType, mscorlib - Name: Entry: 1 - Data: UnityEngine.Quaternion, UnityEngine.CoreModule + Data: UnityEngine.Vector3, UnityEngine.CoreModule - Name: Entry: 8 Data: @@ -421,19 +421,25 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: startScale + Data: startRotation - Name: $v Entry: 7 Data: 22|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: startScale + Data: startRotation - Name: k__BackingField - Entry: 9 - Data: 17 + Entry: 7 + Data: 23|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: UnityEngine.Quaternion, UnityEngine.CoreModule + - Name: + Entry: 8 + Data: - Name: k__BackingField Entry: 9 - Data: 17 + Data: 23 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -448,7 +454,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 23|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 24|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -469,25 +475,19 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: animator + Data: startScale - Name: $v Entry: 7 - Data: 24|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 25|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: animator + Data: startScale - Name: k__BackingField - Entry: 7 - Data: 25|System.RuntimeType, mscorlib - - Name: - Entry: 1 - Data: UnityEngine.Animator, UnityEngine.AnimationModule - - Name: - Entry: 8 - Data: + Entry: 9 + Data: 20 - Name: k__BackingField Entry: 9 - Data: 25 + Data: 20 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -523,19 +523,19 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: renderer + Data: animator - Name: $v Entry: 7 Data: 27|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: renderer + Data: animator - Name: k__BackingField Entry: 7 Data: 28|System.RuntimeType, mscorlib - Name: Entry: 1 - Data: UnityEngine.Renderer, UnityEngine.CoreModule + Data: UnityEngine.Animator, UnityEngine.AnimationModule - Name: Entry: 8 Data: @@ -577,19 +577,19 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: pelletPool + Data: renderer - Name: $v Entry: 7 Data: 30|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: pelletPool + Data: renderer - Name: k__BackingField Entry: 7 Data: 31|System.RuntimeType, mscorlib - Name: Entry: 1 - Data: VRC.SDK3.Components.VRCObjectPool, VRCSDK3 + Data: UnityEngine.Renderer, UnityEngine.CoreModule - Name: Entry: 8 Data: @@ -631,19 +631,19 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: hideUntilUnfrozen + Data: pelletPool - Name: $v Entry: 7 Data: 33|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: hideUntilUnfrozen + Data: pelletPool - Name: k__BackingField Entry: 7 Data: 34|System.RuntimeType, mscorlib - Name: Entry: 1 - Data: System.Boolean, mscorlib + Data: VRC.SDK3.Components.VRCObjectPool, VRCSDK3 - Name: Entry: 8 Data: @@ -685,19 +685,73 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: dead + Data: hideUntilUnfrozen - Name: $v Entry: 7 Data: 36|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: hideUntilUnfrozen + - Name: k__BackingField + Entry: 7 + Data: 37|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Boolean, mscorlib + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 9 + Data: 37 + - 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: 38|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: dead + - Name: $v + Entry: 7 + Data: 39|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: dead - Name: k__BackingField Entry: 9 - Data: 34 + Data: 37 - Name: k__BackingField Entry: 9 - Data: 34 + Data: 37 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -712,7 +766,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 37|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 40|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -736,16 +790,16 @@ MonoBehaviour: Data: kinematic - Name: $v Entry: 7 - Data: 38|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 41|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: kinematic - Name: k__BackingField Entry: 9 - Data: 34 + Data: 37 - Name: k__BackingField Entry: 9 - Data: 34 + Data: 37 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -760,7 +814,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 39|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 @@ -784,70 +838,16 @@ MonoBehaviour: Data: followingPredefinedPath - Name: $v Entry: 7 - Data: 40|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 43|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: followingPredefinedPath - Name: k__BackingField Entry: 9 - Data: 34 + Data: 37 - Name: k__BackingField Entry: 9 - Data: 34 - - 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: 41|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: predefinedPath - - Name: $v - Entry: 7 - Data: 42|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - - Name: k__BackingField - Entry: 1 - Data: predefinedPath - - Name: k__BackingField - Entry: 7 - Data: 43|System.RuntimeType, mscorlib - - Name: - Entry: 1 - Data: UnityEngine.Vector2[], UnityEngine.CoreModule - - Name: - Entry: 8 - Data: - - Name: k__BackingField - Entry: 9 - Data: 43 + Data: 37 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -883,19 +883,19 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: predefinedPathIndex + Data: predefinedPath - Name: $v Entry: 7 Data: 45|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: predefinedPathIndex + Data: predefinedPath - Name: k__BackingField Entry: 7 Data: 46|System.RuntimeType, mscorlib - Name: Entry: 1 - Data: System.Int32, mscorlib + Data: UnityEngine.Vector2[], UnityEngine.CoreModule - Name: Entry: 8 Data: @@ -937,19 +937,19 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: syncedPosition + Data: predefinedPathIndex - Name: $v Entry: 7 Data: 48|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: syncedPosition + Data: predefinedPathIndex - Name: k__BackingField Entry: 7 Data: 49|System.RuntimeType, mscorlib - Name: Entry: 1 - Data: UnityEngine.Vector2, UnityEngine.CoreModule + Data: System.Int32, mscorlib - Name: Entry: 8 Data: @@ -960,8 +960,8 @@ MonoBehaviour: Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib - Name: - Entry: 3 - Data: 1 + Entry: 6 + Data: - Name: Entry: 8 Data: @@ -973,13 +973,7 @@ MonoBehaviour: Data: 50|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 - Data: 1 - - Name: - Entry: 7 - Data: 51|UdonSharp.UdonSyncedAttribute, UdonSharp.Runtime - - Name: - Entry: 8 - Data: + Data: 0 - Name: Entry: 13 Data: @@ -997,25 +991,25 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: targetDirection + Data: syncedPosition - Name: $v Entry: 7 - Data: 52|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 51|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: targetDirection + Data: syncedPosition - Name: k__BackingField Entry: 9 - Data: 49 + Data: 3 - Name: k__BackingField Entry: 9 - Data: 49 + Data: 3 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib - Name: - Entry: 3 - Data: 1 + Entry: 6 + Data: - Name: Entry: 8 Data: @@ -1024,16 +1018,10 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 53|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 52|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 - Data: 1 - - Name: - Entry: 7 - Data: 54|UdonSharp.UdonSyncedAttribute, UdonSharp.Runtime - - Name: - Entry: 8 - Data: + Data: 0 - Name: Entry: 13 Data: @@ -1051,25 +1039,73 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: direction + Data: targetDirection + - Name: $v + Entry: 7 + Data: 53|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: targetDirection + - Name: k__BackingField + Entry: 9 + Data: 3 + - Name: k__BackingField + Entry: 9 + Data: 3 + - 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: 54|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: freezeSeconds - Name: $v Entry: 7 Data: 55|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: direction + Data: freezeSeconds - Name: k__BackingField Entry: 9 - Data: 49 + Data: 13 - Name: k__BackingField Entry: 9 - Data: 49 + Data: 13 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib - Name: - Entry: 3 - Data: 1 + Entry: 6 + Data: - Name: Entry: 8 Data: @@ -1081,67 +1117,7 @@ MonoBehaviour: Data: 56|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 - Data: 1 - - Name: - Entry: 7 - Data: 57|UdonSharp.UdonSyncedAttribute, UdonSharp.Runtime - - Name: - Entry: 8 - Data: - - 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: freezeSeconds - - Name: $v - Entry: 7 - Data: 58|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - - Name: k__BackingField - Entry: 1 - Data: freezeSeconds - - Name: k__BackingField - Entry: 9 - Data: 10 - - Name: k__BackingField - Entry: 9 - Data: 10 - - Name: k__BackingField - Entry: 7 - Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib - - Name: - Entry: 3 - Data: 1 - - Name: - Entry: 8 - Data: - - Name: k__BackingField - Entry: 5 - Data: false - - Name: _fieldAttributes - Entry: 7 - Data: 59|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - - Name: - Entry: 12 - Data: 1 - - Name: - Entry: 7 - Data: 60|UdonSharp.UdonSyncedAttribute, UdonSharp.Runtime - - Name: - Entry: 8 - Data: + Data: 0 - Name: Entry: 13 Data: @@ -1162,22 +1138,22 @@ MonoBehaviour: Data: frozen - Name: $v Entry: 7 - Data: 61|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 57|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: frozen - Name: k__BackingField Entry: 9 - Data: 34 + Data: 37 - Name: k__BackingField Entry: 9 - Data: 34 + Data: 37 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib - Name: - Entry: 3 - Data: 1 + Entry: 6 + Data: - Name: Entry: 8 Data: @@ -1186,16 +1162,10 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 62|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 58|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 - Data: 1 - - Name: - Entry: 7 - Data: 63|UdonSharp.UdonSyncedAttribute, UdonSharp.Runtime - - Name: - Entry: 8 - Data: + Data: 0 - Name: Entry: 13 Data: diff --git a/Assets/Scripts/PacMan.cs b/Assets/Scripts/PacMan.cs index b456d4e..f8c29de 100644 --- a/Assets/Scripts/PacMan.cs +++ b/Assets/Scripts/PacMan.cs @@ -207,7 +207,7 @@ return nextPosition; } - private void UpdateAnimator() + protected override void UpdateAnimator() { // Debug.Log($"{gameObject} UpdateAnimator with direction {direction}, dead {dead}, frozen {frozen}"); if (!gameObject.activeInHierarchy) @@ -316,28 +316,6 @@ renderer.enabled = visible; } - public override Vector2 GetPosition() - { - return (Vector2)transform.localPosition; - } - - public override void SetPosition(Vector2 position) - { - GridMoverTools.SetPosition(position, transform); - } - - public override Vector2 GetDirection() - { - return direction; - } - - public void SetDirection(Vector2 direction) - { - this.direction = direction; - RequestSerialization(); - UpdateAnimator(); - } - public void SetTargetDirection(Vector2 targetDirection) { this.targetDirection = targetDirection; diff --git a/Assets/Scripts/PlayerInput.cs b/Assets/Scripts/PlayerInput.cs index 122ab09..22c4f53 100644 --- a/Assets/Scripts/PlayerInput.cs +++ b/Assets/Scripts/PlayerInput.cs @@ -10,7 +10,7 @@ public class PlayerInput : UdonSharpBehaviour { public bool active; - private GameManager gameController; + private GameManager gameManager; Vector2 inputHorizontal; Vector2 inputVertical; float horizontalValue; @@ -18,9 +18,9 @@ bool horizontalPriority; VRCPlayerApi player; - public void Initialize(GameManager gameController) + public void Initialize(GameManager gameManager) { - this.gameController = gameController; + this.gameManager = gameManager; inputHorizontal = Vector2.zero; inputVertical = Vector2.zero; horizontalPriority = false; @@ -35,7 +35,7 @@ player.SetRunSpeed(0); player.SetStrafeSpeed(0); - gameController.JoystickGrabbed(); + gameManager.JoystickGrabbed(); } public void Deactivate() @@ -46,7 +46,7 @@ player.SetStrafeSpeed(2); active = false; - gameController.JoystickReleased(); + gameManager.JoystickReleased(); } public override void InputJump(bool pressed, UdonInputEventArgs args) @@ -128,6 +128,7 @@ // horizontalPriority = true; SetPriority(true); } + // Debug.Log("Vertical Input Event: " + value + " | Direction: " + direction + " | lastDirection : " + lastDirection); } diff --git a/Assets/Scripts/Sequences/TimeSequenceShared.cs b/Assets/Scripts/Sequences/TimeSequenceShared.cs index fbb4a08..3874a75 100644 --- a/Assets/Scripts/Sequences/TimeSequenceShared.cs +++ b/Assets/Scripts/Sequences/TimeSequenceShared.cs @@ -12,7 +12,7 @@ namespace Marro.PacManUdon // While I'm not a big fan of the partial class solution that I ended up doing (static classes would still be neater, or perhaps separate UdonSharpBehaviour instances), // I'm not redoing this unless I get instantiatable classes before I wrap up this project. bool currentlyInTimeSequence; - bool waitingForTimeSequenceFinish; + bool waitingForTimeSequenceFinalize; bool jumpingToTimeSequence; PacManTimeSequence currentTimeSequence; [UdonSynced] float timeSequenceSecondsPassed; @@ -42,6 +42,7 @@ namespace Marro.PacManUdon { jumpingToTimeSequence = true; TimeSequenceProgressToTime(100000f); + TryFinalizeTimeSequence(); jumpingToTimeSequence = false; } @@ -98,7 +99,39 @@ namespace Marro.PacManUdon } else { - waitingForTimeSequenceFinish = true; + waitingForTimeSequenceFinalize = true; + } + } + + private void TryFinalizeTimeSequence() + { + if (!waitingForTimeSequenceFinalize) + { + return; + } + + TimeSequenceExecuteFinalize(currentTimeSequence); + waitingForTimeSequenceFinalize = false; + } + + private void TimeSequenceSyncWithRemote(bool currentlyInTimeSequence, PacManTimeSequence currentTimeSequence, float timeSequenceProgress) + { + // If the remote is in a time sequence but we're not, or we're in a different time sequence, jump to the remote's time sequence. + if (currentlyInTimeSequence && (!this.currentlyInTimeSequence || currentTimeSequence != this.currentTimeSequence)) + { + StartTimeSequence(currentTimeSequence); + } + + // If we're (now) in a time sequence, jump our progress to match the one on the remote + if (this.currentlyInTimeSequence) + { + TimeSequenceProgressToTime(timeSequenceProgress); + } + + // If the remote has finished it's time sequence and we have one waiting to be finalized, we can do so now + if (!currentlyInTimeSequence) + { + TryFinalizeTimeSequence(); } } diff --git a/Assets/Scripts/SyncedObject.cs b/Assets/Scripts/SyncedObject.cs new file mode 100644 index 0000000..5f8346f --- /dev/null +++ b/Assets/Scripts/SyncedObject.cs @@ -0,0 +1,12 @@ +using System.Collections; +using UdonSharp; +using UnityEngine; + +namespace Assets.Scripts +{ + public abstract class SyncedObject : UdonSharpBehaviour + { + public abstract void AppendSyncedData(byte[][] data, ref int index); + public abstract bool SetSyncedData(byte[] data, ref int index); + } +} \ No newline at end of file diff --git a/Assets/Scripts/SyncedObject.cs.meta b/Assets/Scripts/SyncedObject.cs.meta new file mode 100644 index 0000000..a8fc786 --- /dev/null +++ b/Assets/Scripts/SyncedObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d09fe6fd5a83df9468f5ffcb43d73af3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: