Compare commits

..

6 Commits

Author SHA1 Message Date
878486c92f Small changes 2026-06-11 13:38:01 +02:00
bce6b329c2 Improved network accuracy 2026-06-11 12:25:12 +02:00
f0859d92ac Implemented event subscribers 2026-06-11 12:05:38 +02:00
e75452b145 Fixes 2026-06-11 12:05:12 +02:00
e7968a5753 NetworkManagerTester working 2026-06-10 20:09:41 +02:00
cf39fd5dd9 A lot of older work 2026-06-09 17:45:51 +02:00
22 changed files with 69162 additions and 60671 deletions

61241
Assets/PacManGame.prefab Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 15ac0ed4c56c7784ea3ae9000fc2af1f
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -67,6 +67,9 @@ namespace Marro.PacManUdon
soundManager.Initialize();
intermission2Pole.Initialize(this, ghostManager.Ghosts[0]);
SubscribeToEvent(NetworkEventType.StartGameButtonPressed);
SubscribeToEvent(NetworkEventType.TimeSequenceSync);
HideEverything();
SetScore(0);
@@ -123,7 +126,7 @@ namespace Marro.PacManUdon
private void InitializeNewGame()
{
Debug.Log($"{gameObject} Started new game!");
//Debug.Log($"{gameObject} Started new game!");
SetScore(0);
SetExtraLives(startingExtraLives);
SetLevel(1);
@@ -131,7 +134,7 @@ namespace Marro.PacManUdon
private void InitializeLevel()
{
Debug.Log($"{gameObject} New level started!");
//Debug.Log($"{gameObject} New level started!");
pelletManager.RestoreAllPellets();
@@ -142,7 +145,7 @@ namespace Marro.PacManUdon
private void RestartLevel(bool afterLifeLost = false)
{
Debug.Log($"{gameObject} (Re)started level!");
//Debug.Log($"{gameObject} (Re)started level!");
// SetInGameComponentVisibility(true);
@@ -186,7 +189,7 @@ namespace Marro.PacManUdon
public void GotPowerPellet(Pellet pellet)
{
Debug.Log($"{gameObject} GotPowerPellet");
//Debug.Log($"{gameObject} GotPowerPellet");
if (gameState == PacManGameState.AttractMode)
{
@@ -215,7 +218,7 @@ namespace Marro.PacManUdon
public void GhostCaught(int scoreBonus)
{
Debug.Log($"{gameObject} GhostCaught");
//Debug.Log($"{gameObject} GhostCaught");
if (gameState == PacManGameState.AttractMode)
{
@@ -246,7 +249,7 @@ namespace Marro.PacManUdon
public void Intermission2PoleUpdate()
{
Debug.Log($"{gameObject} Intermission2PoleUpdate");
//Debug.Log($"{gameObject} Intermission2PoleUpdate");
TimeSequenceSkipToNextStep();
}
@@ -394,21 +397,47 @@ namespace Marro.PacManUdon
}
}
public override void CollectSyncedData(byte[] data, ref int offset, NetworkEventType eventType)
public override void CollectSyncedData(byte[] data, ref int index, NetworkEventType eventType)
{
if (eventType == NetworkEventType.TimeSequenceSync)
{
data.Append(currentlyInTimeSequence, ref index);
if (currentlyInTimeSequence)
{
data.AppendAsByte((int)currentTimeSequence, ref index);
data.Append(timeSequenceSecondsPassed, ref index);
}
}
//data[offset++] = new byte[] { NetworkManager.Int32ToByte((int)gameState) };
//data[offset++] = BitConverter.GetBytes(currentlyInTimeSequence);
//data[offset++] = new byte[] { NetworkManager.Int32ToByte((int)currentTimeSequence) };
//data[offset++] = BitConverter.GetBytes(timeSequenceSecondsPassed);
}
public override bool WriteSyncedData(byte[] data, ref int offset, NetworkEventType eventType)
public override bool WriteSyncedData(byte[] data, ref int index, NetworkEventType eventType)
{
if (eventType == NetworkEventType.StartGameButtonPressed)
{
StartGameButtonPressed();
}
if (eventType == NetworkEventType.TimeSequenceSync)
{
var currentlyInTimeSequence = data.ReadBool(ref index);
if (currentlyInTimeSequence)
{
var currentTimeSequence = (PacManTimeSequence)data.ReadByte(ref index);
var timeSequenceSecondsPassed = data.ReadFloat(ref index);
TimeSequenceSyncWithRemote(currentTimeSequence, timeSequenceSecondsPassed);
}
else
{
TimeSequenceTryEndCurrent();
}
}
//SetGameState((PacManGameState)data[offset++]);
//var currentlyInTimeSequence = BitConverter.ToBoolean(data, offset++);

View File

@@ -109,6 +109,8 @@ namespace Marro.PacManUdon
frozenState = PacManGhostFrozenState.Frozen;
Index = index;
SubscribeToEvent(NetworkEventType.GhostUpdate);
}
public void Reset()
@@ -163,13 +165,13 @@ namespace Marro.PacManUdon
SetPosition(nextPosition);
}
private Vector2 ProcessNextPosition(Vector2 position, Vector2 nextPosition)
private Vector2 ProcessNextPosition(Vector2 position, Vector2 nextPosition)
{
if (turnAroundSoon && ghostState == PacManGhostState.Normal
&& GridMoverTools.CrossesTileBorder(position, nextPosition, direction.x != 0, direction.y != 0))
{
SetDirection(direction * -1);
Debug.Log($"{gameObject} turned around to direction {GetDirection()}");
//Debug.Log($"{gameObject} turned around to direction {GetDirection()}");
turnAroundSoon = false;
return nextPosition;
}
@@ -816,7 +818,6 @@ namespace Marro.PacManUdon
inTunnel = data.ReadBool(ref index);
rngState = data.ReadInt(ref index);
turnAroundSoon = data.ReadBool(ref index);
Debug.Log($"{gameObject} turnAroundSoon = {turnAroundSoon}");
speed = data.ReadFloat(ref index);
ghostState = (PacManGhostState)data.ReadByte(ref index);

View File

@@ -74,6 +74,8 @@ namespace Marro.PacManUdon
ghosts[ghostIndex].Initialize(pacMan, blinky, startTransform, homePosition, idlePosition1, idlePosition2, cornerPosition, ghostIndex);
}
SubscribeToEvent(NetworkEventType.GhostUpdate);
}
public void RestartLevel(bool afterLifeLost = false)
@@ -193,6 +195,7 @@ namespace Marro.PacManUdon
}
// Debug.Log($"{gameObject} GhostCaughtQueue with ghost {ghost}");
//networkManager.SendEventSoon(NetworkEventType.TimeSequenceSync);
//networkManager.SendEventSoon(NetworkEventType.GhostUpdate);
ghostScaredQueue.Add(ghost);
@@ -315,7 +318,7 @@ namespace Marro.PacManUdon
public void SetLevel(int level)
{
Debug.Log($"GhostManager: SetLevel {level}");
//Debug.Log($"GhostManager: SetLevel {level}");
SetLevelConstants(level);
int[] privatePelletCounterReleaseValues = PacManConstants.GetGhostHousePrivatePelletCounterLimitForLevel(level);
@@ -376,7 +379,7 @@ namespace Marro.PacManUdon
void SetScattering(bool scattering, bool reverseDirection = true)
{
Debug.Log($"{gameObject} SetScattering: {scattering}");
//Debug.Log($"{gameObject} SetScattering: {scattering}");
foreach (Ghost ghost in ghosts)
{
if (ghost == blinky && elroyLevel > 0) // Once blinky is elroy he no longer scatters
@@ -393,7 +396,7 @@ namespace Marro.PacManUdon
/// </summary>
void SetSharedPelletCounterActive(bool active)
{
Debug.Log($"{gameObject} SetSharedPelletCounterActive {active}");
//Debug.Log($"{gameObject} SetSharedPelletCounterActive {active}");
sharedPelletCounterActive = active;
foreach (Ghost ghost in ghosts)
{
@@ -528,7 +531,7 @@ namespace Marro.PacManUdon
}
ghostScaredQueueArray[i] = (byte)((Ghost)ghost.Reference).Index;
}
Debug.Log($"{gameObject} Sent a ghostScareQueue of length {ghostScaredQueue.Count}");
//Debug.Log($"{gameObject} Sent a ghostScareQueue of length {ghostScaredQueue.Count}");
data.Append(ghostScaredQueueArray, ref index);
}
@@ -578,7 +581,7 @@ namespace Marro.PacManUdon
ghostScaredQueue.Add(ghosts[ghostIndex]);
}
index += ghosts.Length;
Debug.Log($"{gameObject} Read back a ghostScareQueue of length {ghostScaredQueue.Count}");
//Debug.Log($"{gameObject} Read back a ghostScareQueue of length {ghostScaredQueue.Count}");
return true;
}

View File

@@ -36,6 +36,11 @@ namespace Marro.PacManUdon
data.Append(GetDirection(), ref index);
}
public void PadSyncedData(byte[] data, ref int index, NetworkEventType eventType)
{
index += 16;
}
public override bool WriteSyncedData(byte[] data, ref int index, NetworkEventType eventType)
{
SetPosition(data.ReadVector2(ref index));
@@ -43,5 +48,12 @@ namespace Marro.PacManUdon
return true;
}
public bool ConsumeSyncedData(byte[] data, ref int index, NetworkEventType eventType)
{
index += 16;
return true;
}
}
}

View File

@@ -47,7 +47,7 @@ namespace Marro.PacManUdon
public void SetActive(bool isActive)
{
Debug.Log($"({nameof(PacManUdon)} {nameof(Intermission2Pole)}) SetActive {isActive}.");
//Debug.Log($"({nameof(PacManUdon)} {nameof(Intermission2Pole)}) SetActive {isActive}.");
gameObject.SetActive(isActive);
}
@@ -115,7 +115,7 @@ namespace Marro.PacManUdon
public void SetStrechLevel(PoleStrechLevels level)
{
Debug.Log($"({nameof(PacManUdon)} {nameof(Intermission2Pole)}) Set strech level to {level}.");
//Debug.Log($"({nameof(PacManUdon)} {nameof(Intermission2Pole)}) Set strech level to {level}.");
_animator.SetFloat("Strech", GetAnimatorValueForStrechLevel(level));
}

File diff suppressed because it is too large Load Diff

View File

@@ -17,9 +17,13 @@ namespace Marro.PacManUdon
StartGameButtonPressed = 3,
SyncPellets = 4,
GhostUpdate = 5,
TimeSequenceSync = 6,
Pause = 7,
Resume = 8,
Step = 9,
}
public class NetworkManager : UdonSharpBehaviour
public class NetworkManager : SyncedObject
{
// 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.
@@ -60,9 +64,9 @@ namespace Marro.PacManUdon
/// </summary>
[SerializeField] private float pingDelay = 0.3f;
/// <summary>
/// The rate at which updates occur.
/// The time delta at which updates occur.
/// </summary>
[SerializeField] private float updateRate = 0.0166666667f;
[SerializeField] private float updateDelta = 0.0166666667f;
#endregion
#region Constants
@@ -99,9 +103,24 @@ namespace Marro.PacManUdon
#region Private attributes
/// <summary>
/// Objects which are controlled by this <see cref="NetworkManager"/>.
/// Whether <see cref="Initialize"/> has been called successfully.
/// </summary>
private SyncedObject[] syncedObjects;
private bool initialized = false;
/// <summary>
/// Subscribers to each <see cref="NetworkEventType"/>.
/// </summary>
private SyncedObject[][] networkEventSubscribers;
/// <summary>
/// Indices for <see cref="networkEventSubscribers"/>.
/// </summary>
private int[] networkEventSubscribersIndices;
/// <summary>
/// Subscribers for <see cref="SyncedObject.SyncedUpdate"/>.
/// </summary>
private SyncedObject[] syncedUpdateSubscribers;
/// <summary>
/// Offset from system time to network time, including delay.
@@ -113,7 +132,17 @@ namespace Marro.PacManUdon
private float internalTime;
/// <summary>
/// Time at which the latest update occured
/// True if time is paused
/// </summary>
private bool paused;
/// <summary>
/// True if a step should happen next update
/// </summary>
private bool stepNext;
/// <summary>
/// Time at which the next update should occur.
/// </summary>
private float nextUpdateTime;
/// <summary>
@@ -185,16 +214,41 @@ namespace Marro.PacManUdon
#endregion
#region Public fields
private bool ready = false;
/// <summary>
/// Whether this <see cref="NetworkManager"/> is ready to transmit or receive data.
/// If false, networking is disabled and this <see cref="NetworkManager"/> acts as a pass-through.
/// </summary>
public bool Ready { get; private set; } = false;
public bool Ready
{
get => ready;
private set
{
ready = value;
if (DebugImageToIndicateReady != null)
{
DebugImageToIndicateReady.SetFloat("Color", value ? 1 : 0);
}
}
}
/// <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;
public bool Synced
{
get => synced;
private set
{
synced = value;
if (DebugImageToIndicateSynced != null)
{
DebugImageToIndicateSynced.SetFloat("Color", value ? 1 : 0);
}
}
}
private bool synced = false;
/// <summary>
/// The time since last full sync which is currently being simulated.
@@ -216,16 +270,36 @@ namespace Marro.PacManUdon
/// <summary>
/// Is the local user owner?
/// </summary>
public bool IsOwner { get; private set; }
public bool IsOwner
{
get => isOwner;
private set
{
isOwner = value;
if (DebugImageToIndicateOwner != null)
{
DebugImageToIndicateOwner.SetFloat("Color", value ? 1 : 0);
}
}
}
private bool isOwner = false;
#endregion
#region General
/// <summary>
/// Initializes the <see cref="NetworkManager"/>. Call <see cref="Reset"/> afterwards to activate networking.
/// </summary>
public void Initialize()
{
if (initialized)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Tried to call {nameof(Initialize)} when already initialized!");
return;
}
if (!BitConverter.IsLittleEndian)
{
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Fatal: NetworkManager only supports little endian! Network sync will not be possible.");
Ready = false;
return;
}
@@ -234,15 +308,46 @@ namespace Marro.PacManUdon
root = transform.parent.gameObject;
}
syncedObjects = root.GetComponentsInChildren<SyncedObject>(includeInactive: true);
foreach (var obj in syncedObjects)
InitializeSubscribers();
initialized = true;
Reset();
}
private void InitializeSubscribers()
{
syncedUpdateSubscribers = root.GetComponentsInChildren<SyncedObject>(includeInactive: true);
foreach (var obj in syncedUpdateSubscribers)
{
obj.networkManager = this;
}
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Found {syncedObjects.Length} {nameof(SyncedObject)} in children of {root.name}.");
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Found {syncedUpdateSubscribers.Length} {nameof(SyncedObject)} in children of {root.name}.");
SetOwner(Networking.IsOwner(gameObject));
const int eventTypeCount = byte.MaxValue + 1;
networkEventSubscribers = new SyncedObject[eventTypeCount][];
networkEventSubscribersIndices = new int[eventTypeCount];
}
public void Reset()
{
if (!initialized)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Tried to call {nameof(Reset)} while not initialized. Call {nameof(Initialize)} first.");
return;
}
if (tester == null)
{
IsOwner = Networking.IsOwner(gameObject);
}
else
{
IsOwner = tester.ShouldBeOwner(this);
}
ClearBuffer();
@@ -256,26 +361,63 @@ namespace Marro.PacManUdon
SyncedDeltaTime = Time.fixedDeltaTime;
nextUpdateTime = SyncedTime;
if (!Synced)
{
RequestEvent(NetworkEventType.FullSync); // See if we can sync up
}
Ready = true;
// Sync up
if (IsOwner)
{
SendEventSoon(NetworkEventType.FullSyncForced);
}
else
{
RequestEvent(NetworkEventType.FullSync);
}
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Initialized, time offset: {offsetTime}");
}
public void Update()
{
if (!Ready)
if (!initialized)
{
return;
}
// Fetch the current time
// Get our target time
UpdateInternalTime();
// Forwards simulated time by updateDelta until we're caught up
while (nextUpdateTime <= internalTime)
{
PerformFixedSyncedUpdate();
}
}
private void UpdateInternalTime()
{
var delta = Time.fixedTime - offsetTime - internalTime;
if (!paused)
{
// Continue time like normal
internalTime += delta;
}
else if (paused && !stepNext)
{
// Since we're paused, increase our offset from Unity's time
offsetTime += delta;
}
else
{
// Step forward by exactly updateDelta, apply the remainder to our offset
offsetTime += delta - updateDelta;
internalTime += updateDelta;
stepNext = false;
}
}
private void PerformFixedSyncedUpdate()
{
if (Ready)
{
if (IsOwner)
@@ -285,31 +427,22 @@ namespace Marro.PacManUdon
}
else
{
ApplyReceivedEvents(); // See if there's events that need to be replayed
ApplyReceivedEvents(); // See if there's events after last update that need to be replayed
}
}
// Forwards simulated time at the updateRate pace
while (nextUpdateTime <= internalTime)
{
ProgressSyncedTime(nextUpdateTime);
PerformFixedSyncedUpdate();
nextUpdateTime = SyncedTime + updateRate;
}
ProgressSyncedTime(nextUpdateTime);
CallSyncedUpdate();
nextUpdateTime = SyncedTime + updateDelta;
}
private void UpdateInternalTime()
{
internalTime = Time.fixedTime - offsetTime;
}
private void PerformFixedSyncedUpdate()
private void CallSyncedUpdate()
{
IsEventUpdate = false;
for (int i = 0; i < syncedObjects.Length; i++)
for (int i = 0; i < syncedUpdateSubscribers.Length; i++)
{
var obj = syncedObjects[i];
var obj = syncedUpdateSubscribers[i];
if (obj.gameObject.activeInHierarchy)
{
@@ -348,14 +481,30 @@ namespace Marro.PacManUdon
}
}
private void SetOwner(bool isOwner)
{
IsOwner = isOwner;
private SyncedObject[] GetEventSubscribers(NetworkEventType eventType) => networkEventSubscribers[(int)eventType];
if (DebugImageToIndicateOwner != null)
public void SubscribeToEvent(SyncedObject syncedObject, NetworkEventType eventType)
{
// This is inefficient, but I'd rather initialize slowly than perform bounds checks in often called code
var eventTypeIndex = (int)eventType;
var subscribers = networkEventSubscribers[eventTypeIndex];
int subscribersIndex = networkEventSubscribersIndices[eventTypeIndex];
if (subscribers == null)
{
DebugImageToIndicateOwner.SetFloat("Color", isOwner ? 1 : 0);
subscribers = new SyncedObject[1];
}
else
{
subscribers = new SyncedObject[subscribersIndex+1];
Array.Copy(networkEventSubscribers[eventTypeIndex], subscribers, subscribersIndex);
}
subscribers[subscribersIndex] = syncedObject;
networkEventSubscribers[eventTypeIndex] = subscribers;
networkEventSubscribersIndices[eventTypeIndex] = subscribersIndex;
}
#endregion
@@ -412,9 +561,14 @@ namespace Marro.PacManUdon
InitializeEvent(eventType, timestamp, eventId, out byte[] data, out var index);
foreach (var obj in syncedObjects)
var subscibers = GetEventSubscribers(eventType);
if (subscibers != null)
{
obj.CollectSyncedData(data, ref index, eventType);
foreach (var obj in subscibers)
{
obj.CollectSyncedData(data, ref index, eventType);
}
}
// Validate and fill in event size
@@ -455,6 +609,10 @@ namespace Marro.PacManUdon
{
RequestSerialization();
serializationRequested = true;
if (tester != null)
{
tester.RequestSerializationTest();
}
}
[NetworkCallable]
@@ -481,7 +639,7 @@ namespace Marro.PacManUdon
private void ProgressPingTime()
{
if (eventsQueueIndex > 0
if (eventsQueueIndex > 0 && !serializationRequested
&& internalTime - lastEventTransmissionTime >= pingDelay)
{
RequestSerializationForEvents();
@@ -509,16 +667,19 @@ namespace Marro.PacManUdon
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Serializing {eventsQueueIndex} event(s), eventTransmissionHistory is now {ArrayToString(eventTransmissionHistory)} with index {eventTransmissionHistoryIndex}");
}
public override void OnPostSerialization(SerializationResult result)
public override void OnPostSerialization(SerializationResult result) => OnPostSerializationInternal(result.success, result.byteCount);
// Version of OnPostSerialization which does not require instantiating SerializationResult, so that it can be called for debugging purposes.
public void OnPostSerializationInternal(bool success, int byteCount)
{
if (!Ready || !IsOwner || networkedData.Length == 0)
{
return;
}
if (!result.success)
if (!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 {byteCount} bytes.");
return;
}
@@ -553,6 +714,11 @@ namespace Marro.PacManUdon
}
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, "RequestEventReceived", eventType);
if (tester != null)
{
tester.RequestEvent(eventType);
}
}
private void StoreIncomingData()
@@ -618,7 +784,7 @@ namespace Marro.PacManUdon
QueueEventInBuffer(@event);
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)} Queued event with id {eventId}");
//Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)} Queued event with id {eventId}");
}
else
{
@@ -656,7 +822,7 @@ namespace Marro.PacManUdon
{
IsEventUpdate = true;
while (eventsQueueIndex > 0 && nextEventTime <= internalTime)
while (eventsQueueIndex > 0 && nextEventTime <= SyncedTime)
{
var success = ApplyEvent(eventsQueue[0]);
@@ -686,20 +852,27 @@ namespace Marro.PacManUdon
ProgressSyncedTime(timestamp);
foreach (var obj in syncedObjects)
{
obj.SyncedUpdate();
}
var subscribers = GetEventSubscribers(eventType);
foreach (var obj in syncedObjects)
{
var success = obj.WriteSyncedData(@event, ref index, eventType);
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) ApplyEvent with dt {SyncedDeltaTime}");
if (!success)
if (subscribers != null)
{
foreach (var obj in subscribers)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Malformed data reported by {obj.name} during event type {eventType}!");
HandleError(true);
return false;
obj.SyncedUpdate();
}
foreach (var obj in subscribers)
{
var success = obj.WriteSyncedData(@event, ref index, eventType);
if (!success)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Malformed data reported by {obj.name} during event type {eventType}!");
HandleError(true);
return false;
}
}
}
@@ -819,7 +992,7 @@ namespace Marro.PacManUdon
HandleError(true);
return;
}
if (nextEventTime < SyncedTime)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) New event timestamp is earlier than our current synced time by {SyncedTime - nextEventTime} seconds! nextEventTime: {nextEventTime} SyncedTime: {SyncedTime}, internalTime: {internalTime}");
@@ -869,7 +1042,7 @@ namespace Marro.PacManUdon
}
bool newOwnerIsLocalPlayer = newOwner == Networking.LocalPlayer;
SetOwner(newOwnerIsLocalPlayer);
IsOwner = newOwnerIsLocalPlayer;
if (newOwnerIsLocalPlayer)
{
@@ -936,6 +1109,31 @@ namespace Marro.PacManUdon
}
#endregion
#region SyncedData
public override void CollectSyncedData(byte[] data, ref int index, NetworkEventType eventType)
{
// Nothing
}
public override bool WriteSyncedData(byte[] data, ref int index, NetworkEventType eventType)
{
switch (eventType)
{
case NetworkEventType.Pause:
Pause();
break;
case NetworkEventType.Resume:
Resume();
break;
case NetworkEventType.Step:
Step();
break;
}
return true;
}
#endregion
#region Debug
public void SimulateSyncToTimestamp(float timestamp)
{
@@ -965,6 +1163,32 @@ namespace Marro.PacManUdon
/// </summary>
[SerializeField] private Animator DebugImageToIndicateOwner;
/// <summary>
/// An animator which visualizes whether the NetworkManager is synced.
/// </summary>
[SerializeField] private Animator DebugImageToIndicateSynced;
/// <summary>
/// An animator which visualizes whether the NetworkManager is synced.
/// </summary>
[SerializeField] private Animator DebugImageToIndicateReady;
private NetworkManagerTester tester;
public void SetNetworkManagerTester(NetworkManagerTester tester)
{
this.tester = tester;
}
public byte[] NetworkedData
{
get => networkedData;
set => networkedData = value;
}
public bool SerializationRequested => serializationRequested;
public void SetIsOwner(bool isOwner) => IsOwner = isOwner;
public void DoFullSync()
{
SendEventSoon(NetworkEventType.FullSync);
@@ -979,6 +1203,47 @@ namespace Marro.PacManUdon
{
SendEventSoon(NetworkEventType.GhostUpdate);
}
public void DoTimeSequenceSync()
{
SendEventSoon(NetworkEventType.TimeSequenceSync);
}
public void Pause()
{
paused = true;
stepNext = false;
}
private void Resume()
{
paused = false;
stepNext = false;
}
private void Step()
{
paused = true;
stepNext = true;
}
public void PauseButtonPressed()
{
Pause();
SendEventSoon(NetworkEventType.Pause);
}
public void ResumeButtonPressed()
{
Resume();
SendEventSoon(NetworkEventType.Resume);
}
public void StepButtonPressed()
{
Step();
SendEventSoon(NetworkEventType.Step);
}
#endregion
}
}

View File

@@ -50,6 +50,8 @@ namespace Marro.PacManUdon
hideUntilUnfrozen = false;
startPosition = startTransform.localPosition;
startRotation = startTransform.localRotation;
SubscribeToEvent(NetworkEventType.PacManTurn);
}
public void Reset()
@@ -64,7 +66,7 @@ namespace Marro.PacManUdon
SetDead(false);
animator.SetTrigger("Reset");
Debug.Log($"{gameObject} Reset! Position is now {GetPosition()}.");
//Debug.Log($"{gameObject} Reset! Position is now {GetPosition()}.");
}
public override void SyncedUpdate()
@@ -151,7 +153,11 @@ namespace Marro.PacManUdon
SetDirection(inputDirection + new Vector2(GridMoverTools.PositionToGrid(nextPosition).x - nextPosition.x, 0).normalized);
}
SetTargetDirection(inputDirection); // This is the direction most logic should assume pacman is moving, the actual direction may be different due to cornering
networkManager.SendEventSoon(NetworkEventType.PacManTurn);
if (!followingPredefinedPath)
{
networkManager.SendEventSoon(NetworkEventType.PacManTurn);
}
}
return nextPosition;
@@ -336,11 +342,18 @@ namespace Marro.PacManUdon
public override void CollectSyncedData(byte[] data, ref int index, NetworkEventType eventType)
{
if (eventType != NetworkEventType.PacManTurn || kinematic || frozen || !enabled)
if (eventType != NetworkEventType.PacManTurn)
{
return;
}
if (kinematic || frozen || !enabled)
{
index += 8;
base.PadSyncedData(data, ref index, eventType);
return;
}
data.Append(targetDirection, ref index);
base.CollectSyncedData(data, ref index, eventType);
@@ -348,11 +361,18 @@ namespace Marro.PacManUdon
public override bool WriteSyncedData(byte[] data, ref int index, NetworkEventType eventType)
{
if (eventType != NetworkEventType.PacManTurn || kinematic || frozen || !enabled)
if (eventType != NetworkEventType.PacManTurn)
{
return true;
}
if (kinematic || frozen || !enabled)
{
index += 8;
base.ConsumeSyncedData(data, ref index, eventType);
return true;
}
SetTargetDirection(data.ReadVector2(ref index));
return base.WriteSyncedData(data, ref index, eventType);

View File

@@ -28,6 +28,8 @@ namespace Marro.PacManUdon
SetPowerPelletsBlink(false);
RestoreAllPellets();
SubscribeToEvent(NetworkEventType.SyncPellets);
}
public override void SyncedUpdate()

View File

@@ -18,12 +18,9 @@ namespace Marro.PacManUdon
private void StartTimeSequence(PacManTimeSequence timeSequence)
{
Debug.Log($"StartTimeSequence: {timeSequence}");
//Debug.Log($"StartTimeSequence: {timeSequence}");
if (currentlyInTimeSequence)
{
TimeSequenceEndCurrent();
}
TimeSequenceTryEndCurrent();
TimeSequencePrepareForStart(timeSequence);
@@ -35,12 +32,24 @@ namespace Marro.PacManUdon
TimeSequenceProgressToTime(timeSequenceSecondsPassed);
}
private void TimeSequenceEndCurrent()
private void TimeSequenceTryEndCurrent()
{
if (!currentlyInTimeSequence)
{
return;
}
//Debug.Log($"{gameObject} TimeSequenceEndCurrent");
jumpingToTimeSequence = true;
TimeSequenceProgressToTime(100000f);
Debug.LogWarning($"{gameObject} TimeSequenceEndCurrent");
TryFinalizeTimeSequence();
if (waitingForTimeSequenceFinalize)
{
TimeSequenceExecuteFinalize(currentTimeSequence);
}
jumpingToTimeSequence = false;
}
@@ -56,7 +65,7 @@ namespace Marro.PacManUdon
private void TimeSequenceSkipToNextStep()
{
Debug.Log($"{gameObject} TimeSequenceSkipToNextStep");
//Debug.Log($"{gameObject} TimeSequenceSkipToNextStep");
if (timeSequenceProgress < timeSequenceKeyframeTimes.Length)
{
TimeSequenceProgressToTime(timeSequenceKeyframeTimes[timeSequenceProgress]);
@@ -79,61 +88,40 @@ namespace Marro.PacManUdon
if (timeSequenceProgress >= timeSequenceKeyframeTimes.Length)
{
currentlyInTimeSequence = false;
TimeSequencePrepareForFinish(currentTimeSequence);
TimeSequenceFinish(currentTimeSequence);
break;
}
}
}
private void TimeSequencePrepareForFinish(PacManTimeSequence timeSequence)
private void TimeSequenceFinish(PacManTimeSequence timeSequence)
{
//if (networkManager.IsOwner)
//{
Debug.LogWarning($"{gameObject} TimeSequencePrepareForFinish");
TimeSequenceExecuteFinalize(timeSequence);
networkManager.SendEventSoon(NetworkEventType.TimeSequenceSync);
if (!jumpingToTimeSequence)
{
TimeSequenceExecuteFinished(timeSequence);
}
//}
//else
//{
// waitingForTimeSequenceFinalize = true;
//}
}
private void TryFinalizeTimeSequence()
private void TimeSequenceSyncWithRemote(PacManTimeSequence currentTimeSequence, float timeSequenceSecondsPassed)
{
if (!waitingForTimeSequenceFinalize)
// If the remote is in a time sequence but we're not, or we're in a different time sequence, or if we're behind,
// jump to the remote's time sequence.
if (!currentlyInTimeSequence
|| currentTimeSequence != this.currentTimeSequence
|| timeSequenceSecondsPassed < this.timeSequenceSecondsPassed)
{
return;
StartTimeSequence(currentTimeSequence);
}
TimeSequenceExecuteFinalize(currentTimeSequence);
waitingForTimeSequenceFinalize = false;
// If we're (now) in a time sequence, jump our progress to match the one on the remote
if (currentlyInTimeSequence)
{
TimeSequenceProgressToTime(timeSequenceSecondsPassed);
}
}
//private void TimeSequenceSyncWithRemote(bool currentlyInTimeSequence, PacManTimeSequence currentTimeSequence, float timeSequenceSecondsPassed)
//{
// // 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(timeSequenceSecondsPassed);
// }
// // 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();
// }
//}
#region Events
public void JumpToTimeSequenceAttractScreenIntroduction()
@@ -244,7 +232,7 @@ namespace Marro.PacManUdon
private void TimeSequenceExecuteStep(PacManTimeSequence timeSequence, int sequenceProgress)
{
Debug.Log($"{gameObject} Triggered time sequence step for sequence {currentTimeSequence} with progress {sequenceProgress}");
//Debug.Log($"{gameObject} Triggered time sequence step for sequence {currentTimeSequence} with progress {sequenceProgress}");
switch (timeSequence)
{
default:
@@ -298,7 +286,7 @@ namespace Marro.PacManUdon
private void TimeSequenceExecuteFinalize(PacManTimeSequence timeSequence)
{
Debug.Log($"{gameObject} Triggered time sequence finalize for sequence {currentTimeSequence}");
//Debug.Log($"{gameObject} Triggered time sequence finalize for sequence {currentTimeSequence}");
switch (timeSequence)
{
default:
@@ -342,7 +330,7 @@ namespace Marro.PacManUdon
private void TimeSequenceExecuteFinished(PacManTimeSequence timeSequence)
{
Debug.Log($"{gameObject} Triggered time sequence finished for sequence {currentTimeSequence}");
//Debug.Log($"{gameObject} Triggered time sequence finished for sequence {currentTimeSequence}");
switch (timeSequence)
{
default:

View File

@@ -9,7 +9,9 @@ namespace Marro.PacManUdon
public NetworkManager networkManager;
public virtual void SyncedUpdate() { }
public abstract void CollectSyncedData(byte[] data, ref int index, NetworkEventType eventType);
public abstract bool WriteSyncedData(byte[] data, ref int index, NetworkEventType eventType);
public virtual void CollectSyncedData(byte[] data, ref int index, NetworkEventType eventType) { }
public virtual bool WriteSyncedData(byte[] data, ref int index, NetworkEventType eventType) { return false; }
protected void SubscribeToEvent(NetworkEventType eventType) => networkManager.SubscribeToEvent(this, eventType);
}
}

View File

@@ -0,0 +1,460 @@
%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: NetworkManagerSyncTester
m_EditorClassIdentifier:
serializedUdonProgramAsset: {fileID: 11400000, guid: b33acf2ffaef28f49ba36d29b13cf487, type: 2}
udonAssembly:
assemblyError:
sourceCsScript: {fileID: 11500000, guid: cbbf384cde136444d9f640ff9f3445cf, type: 3}
scriptVersion: 2
compiledVersion: 2
behaviourSyncMode: 0
hasInteractEvent: 0
scriptID: -7942820763917989394
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: networkManager1
- Name: $v
Entry: 7
Data: 2|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: networkManager1
- Name: <UserType>k__BackingField
Entry: 7
Data: 3|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: Marro.PacManUdon.NetworkManager, Assembly-CSharp
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 7
Data: 4|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: VRC.Udon.UdonBehaviour, VRC.Udon
- Name:
Entry: 8
Data:
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: 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: gridMovers1
- Name: $v
Entry: 7
Data: 7|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: gridMovers1
- Name: <UserType>k__BackingField
Entry: 7
Data: 8|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: Marro.PacManUdon.GridMover[], Assembly-CSharp
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 7
Data: 9|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: UnityEngine.Component[], UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: true
- Name: _fieldAttributes
Entry: 7
Data: 10|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 1
- Name:
Entry: 7
Data: 11|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: networkManager2
- Name: $v
Entry: 7
Data: 12|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: networkManager2
- Name: <UserType>k__BackingField
Entry: 9
Data: 3
- Name: <SystemType>k__BackingField
Entry: 9
Data: 4
- 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: true
- Name: _fieldAttributes
Entry: 7
Data: 13|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 1
- Name:
Entry: 7
Data: 14|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: gridMovers2
- Name: $v
Entry: 7
Data: 15|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: gridMovers2
- Name: <UserType>k__BackingField
Entry: 9
Data: 8
- Name: <SystemType>k__BackingField
Entry: 9
Data: 9
- 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: true
- Name: _fieldAttributes
Entry: 7
Data: 16|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 1
- Name:
Entry: 7
Data: 17|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: debugImageToIndicateSynced
- Name: $v
Entry: 7
Data: 18|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: debugImageToIndicateSynced
- Name: <UserType>k__BackingField
Entry: 7
Data: 19|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: UnityEngine.Animator, UnityEngine.AnimationModule
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 19
- 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: true
- Name: _fieldAttributes
Entry: 7
Data: 20|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 1
- Name:
Entry: 7
Data: 21|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: captureTime
- Name: $v
Entry: 7
Data: 22|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: captureTime
- Name: <UserType>k__BackingField
Entry: 7
Data: 23|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Single, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 23
- 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: 24|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: positions
- Name: $v
Entry: 7
Data: 25|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: positions
- Name: <UserType>k__BackingField
Entry: 7
Data: 26|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: UnityEngine.Vector2[], UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- 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: 27|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: 13
Data:
- Name:
Entry: 8
Data:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bcf028de1e758ca45bcd8834df0b821c
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,99 @@
using Marro.PacManUdon;
using Newtonsoft.Json.Linq;
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
public class NetworkManagerSyncTester : UdonSharpBehaviour
{
[SerializeField] NetworkManager networkManager1;
[SerializeField] GridMover[] gridMovers1;
[SerializeField] NetworkManager networkManager2;
[SerializeField] GridMover[] gridMovers2;
[SerializeField] Animator debugImageToIndicateSynced;
private float captureTime;
private Vector2[] positions;
public void Update()
{
if (!networkManager1.Synced || !networkManager2.Synced)
{
positions = null;
return;
}
if (positions == null)
{
positions = GetPositions(gridMovers1);
captureTime = networkManager1.SyncedTime;
}
var remoteTime = networkManager2.SyncedTime;
if (captureTime > remoteTime)
{
return;
}
if (captureTime < remoteTime)
{
Debug.Log($"{nameof(NetworkManagerSyncTester)} Skipping check");
positions = null;
return;
}
bool equal = IsEqual(remoteTime);
SetIndicator(equal);
positions = null;
}
private bool IsEqual(float remoteTime)
{
var positions2 = GetPositions(gridMovers2);
for (int i = 0; i < positions.Length; i++)
{
var gridMover1 = gridMovers1[i];
var gridMover1Position = positions[i];
var gridMover2 = gridMovers2[i];
var gridMover2Position = positions2[i];
var equal = gridMover1Position == gridMover2Position;
if (!equal)
{
Debug.LogWarning($"{nameof(NetworkManagerSyncTester)} Desync found:\n{gridMover1.name} {gridMover1Position} (at {captureTime}) != {gridMover2.name} {gridMover2Position} (at {remoteTime})");
networkManager1.Pause();
networkManager2.Pause();
return false;
}
}
return true;
}
private void SetIndicator(bool value)
{
if (debugImageToIndicateSynced != null)
{
debugImageToIndicateSynced.SetFloat("Color", value ? 1 : 0);
}
}
private Vector2[] GetPositions(GridMover[] gridMovers)
{
var length = gridMovers.Length;
var positions = new Vector2[length];
for (int i = 0; i < length; i++)
{
positions[i] = gridMovers[i].GetPosition();
}
return positions;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cbbf384cde136444d9f640ff9f3445cf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,340 @@
%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: NetworkManagerTester
m_EditorClassIdentifier:
serializedUdonProgramAsset: {fileID: 11400000, guid: 2a95858b6f853584c8e55a5140383df5, type: 2}
udonAssembly:
assemblyError:
sourceCsScript: {fileID: 11500000, guid: 8261cb80d1b7e5f45b0b9afd3f6bb801, type: 3}
scriptVersion: 2
compiledVersion: 2
behaviourSyncMode: 0
hasInteractEvent: 0
scriptID: 3371975218947168961
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: 5
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: networkManagers
- Name: $v
Entry: 7
Data: 2|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: networkManagers
- Name: <UserType>k__BackingField
Entry: 7
Data: 3|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: Marro.PacManUdon.NetworkManager[], Assembly-CSharp
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 7
Data: 4|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: UnityEngine.Component[], UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: 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: interval
- Name: $v
Entry: 7
Data: 7|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: interval
- Name: <UserType>k__BackingField
Entry: 7
Data: 8|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Single, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 8
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: true
- Name: _fieldAttributes
Entry: 7
Data: 9|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 1
- Name:
Entry: 7
Data: 10|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: ownerIndex
- Name: $v
Entry: 7
Data: 11|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: ownerIndex
- Name: <UserType>k__BackingField
Entry: 7
Data: 12|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Int32, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 12
- 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: true
- Name: _fieldAttributes
Entry: 7
Data: 13|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 1
- Name:
Entry: 7
Data: 14|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: countdown
- Name: $v
Entry: 7
Data: 15|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: countdown
- Name: <UserType>k__BackingField
Entry: 9
Data: 8
- Name: <SystemType>k__BackingField
Entry: 9
Data: 8
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 16|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: serializationRequested
- Name: $v
Entry: 7
Data: 17|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: serializationRequested
- Name: <UserType>k__BackingField
Entry: 7
Data: 18|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Boolean, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 18
- 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: 19|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: 13
Data:
- Name:
Entry: 8
Data:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 46452140f2a4ee7458e4f4e13fea6578
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,99 @@
using Marro.PacManUdon;
using System;
using UdonSharp;
using UnityEngine;
public class NetworkManagerTester : UdonSharpBehaviour
{
[SerializeField] private NetworkManager[] networkManagers;
[SerializeField] private float interval = 0.1f;
[SerializeField] private int ownerIndex = 0;
private float countdown = 0;
private bool serializationRequested;
private void Start()
{
foreach (var networkManager in networkManagers)
{
networkManager.SetNetworkManagerTester(this);
if (networkManager.Ready)
{
networkManager.Reset();
}
}
}
private void FixedUpdate()
{
countdown -= Time.deltaTime;
if (countdown > 0)
{
return;
}
countdown = interval;
if (!serializationRequested)
{
return;
}
var source = networkManagers[ownerIndex];
var data = PerformSerialization(source);
Debug.Log($"{nameof(NetworkManagerTester)} Transferring {data.Length} bytes.");
foreach (var target in networkManagers)
{
if (target == source)
{
continue;
}
PerformDeserialization(target, data);
}
serializationRequested = false;
}
private byte[] PerformSerialization(NetworkManager networkManager)
{
networkManager.OnPreSerialization();
var data = networkManager.NetworkedData;
networkManager.OnPostSerializationInternal(true, data.Length) ;
return data;
}
private byte[] PerformDeserialization(NetworkManager networkManager, byte[] data)
{
networkManager.NetworkedData = data;
networkManager.OnDeserialization();
return data;
}
public bool ShouldBeOwner(NetworkManager manager) => Array.IndexOf(networkManagers, manager) == ownerIndex;
public void RequestSerializationTest()
{
serializationRequested = true;
}
public void RequestEvent(NetworkEventType eventType)
{
foreach (var target in networkManagers)
{
if (!target.IsOwner || !target.SerializationRequested)
{
continue;
}
Debug.Log($"{nameof(NetworkManagerTester)} Requested event with type {eventType}.");
target.RequestEventReceived(eventType);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8261cb80d1b7e5f45b0b9afd3f6bb801
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: