Implemented event subscribers

This commit is contained in:
2026-06-11 12:05:38 +02:00
parent e75452b145
commit f0859d92ac
10 changed files with 6684 additions and 62732 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -67,6 +67,9 @@ namespace Marro.PacManUdon
soundManager.Initialize(); soundManager.Initialize();
intermission2Pole.Initialize(this, ghostManager.Ghosts[0]); intermission2Pole.Initialize(this, ghostManager.Ghosts[0]);
SubscribeToEvent(NetworkEventType.StartGameButtonPressed);
SubscribeToEvent(NetworkEventType.TimeSequenceSync);
HideEverything(); HideEverything();
SetScore(0); SetScore(0);

View File

@@ -109,6 +109,8 @@ namespace Marro.PacManUdon
frozenState = PacManGhostFrozenState.Frozen; frozenState = PacManGhostFrozenState.Frozen;
Index = index; Index = index;
SubscribeToEvent(NetworkEventType.GhostUpdate);
} }
public void Reset() public void Reset()

View File

@@ -74,6 +74,8 @@ namespace Marro.PacManUdon
ghosts[ghostIndex].Initialize(pacMan, blinky, startTransform, homePosition, idlePosition1, idlePosition2, cornerPosition, ghostIndex); ghosts[ghostIndex].Initialize(pacMan, blinky, startTransform, homePosition, idlePosition1, idlePosition2, cornerPosition, ghostIndex);
} }
SubscribeToEvent(NetworkEventType.GhostUpdate);
} }
public void RestartLevel(bool afterLifeLost = false) public void RestartLevel(bool afterLifeLost = false)

File diff suppressed because it is too large Load Diff

View File

@@ -3,10 +3,8 @@ using System.Text;
using TMPro; using TMPro;
using UdonSharp; using UdonSharp;
using UnityEngine; using UnityEngine;
using UnityEngine.Android;
using VRC.SDK3.UdonNetworkCalling; using VRC.SDK3.UdonNetworkCalling;
using VRC.SDKBase; using VRC.SDKBase;
using VRC.SDKBase.Midi;
using VRC.Udon.Common; using VRC.Udon.Common;
namespace Marro.PacManUdon namespace Marro.PacManUdon
@@ -48,11 +46,6 @@ namespace Marro.PacManUdon
// [7]: (byte) Type of event. 0 = Full Sync, which is used to sync up from an undefinted state. // [7]: (byte) Type of event. 0 = Full Sync, which is used to sync up from an undefinted state.
// [+]: Event-specific data. // [+]: Event-specific data.
#region External settings
[SerializeField] private SyncedObject[] networkEventSubscribersFlat;
[SerializeField] private int[] networkEventSubscribersFlatSegmentLengths;
#endregion
#region Settings #region Settings
/// <summary> /// <summary>
/// The root from which this <see cref="NetworkManager"/> will look for <see cref="SyncedObject"/> to control. /// The root from which this <see cref="NetworkManager"/> will look for <see cref="SyncedObject"/> to control.
@@ -119,6 +112,11 @@ namespace Marro.PacManUdon
/// </summary> /// </summary>
private SyncedObject[][] networkEventSubscribers; private SyncedObject[][] networkEventSubscribers;
/// <summary>
/// Indices for <see cref="networkEventSubscribers"/>.
/// </summary>
private int[] networkEventSubscribersIndices;
/// <summary> /// <summary>
/// Subscribers for <see cref="SyncedObject.SyncedUpdate"/>. /// Subscribers for <see cref="SyncedObject.SyncedUpdate"/>.
/// </summary> /// </summary>
@@ -310,66 +308,28 @@ namespace Marro.PacManUdon
root = transform.parent.gameObject; root = transform.parent.gameObject;
} }
if (!TryGetNetworkEventSubscribers(out networkEventSubscribers)) InitializeSubscribers();
{
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Fatal: Invalid NetworkEventSubscribers configuration! Network sync will not be possible.");
return;
}
syncedUpdateSubscribers = root.GetComponentsInChildren<SyncedObject>(includeInactive: true);
AssignNetworkManagerReferencesToSubscribers();
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Found {syncedUpdateSubscribers.Length} {nameof(SyncedObject)} in children of {root.name}.");
initialized = true; initialized = true;
Reset(); Reset();
} }
private bool TryGetNetworkEventSubscribers(out SyncedObject[][] result) private void InitializeSubscribers()
{ {
result = new SyncedObject[0][]; syncedUpdateSubscribers = root.GetComponentsInChildren<SyncedObject>(includeInactive: true);
return true;
var values = networkEventSubscribersFlat;
var lengths = networkEventSubscribersFlatSegmentLengths;
result = new SyncedObject[lengths.Length][];
var index = 0;
foreach (var length in lengths)
{
if (index + length >= values.Length)
{
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) {nameof(TryGetNetworkEventSubscribers)}: Lengths sum is larger than values.");
return false;
}
result[index] = new SyncedObject[length];
Array.Copy(values, index, result, 0, length);
index += length;
}
if (index != values.Length)
{
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) {nameof(TryGetNetworkEventSubscribers)}: Lengths sum is smaller than values.");
}
return true;
}
private void AssignNetworkManagerReferencesToSubscribers()
{
// This results in a lot of duplicated assignments, but the alternative is deduplicating and unfortunately Udon does not have a good method for this.
foreach (var obj in syncedUpdateSubscribers) foreach (var obj in syncedUpdateSubscribers)
{ {
obj.networkManager = this; obj.networkManager = this;
} }
foreach (var obj in networkEventSubscribersFlat) Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Found {syncedUpdateSubscribers.Length} {nameof(SyncedObject)} in children of {root.name}.");
{
obj.networkManager = this; const int eventTypeCount = byte.MaxValue + 1;
}
networkEventSubscribers = new SyncedObject[eventTypeCount][];
networkEventSubscribersIndices = new int[eventTypeCount];
} }
public void Reset() public void Reset()
@@ -401,6 +361,8 @@ namespace Marro.PacManUdon
SyncedDeltaTime = Time.fixedDeltaTime; SyncedDeltaTime = Time.fixedDeltaTime;
nextUpdateTime = SyncedTime; nextUpdateTime = SyncedTime;
Ready = true;
// Sync up // Sync up
if (IsOwner) if (IsOwner)
{ {
@@ -411,8 +373,6 @@ namespace Marro.PacManUdon
RequestEvent(NetworkEventType.FullSync); RequestEvent(NetworkEventType.FullSync);
} }
Ready = true;
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Initialized, time offset: {offsetTime}"); Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Initialized, time offset: {offsetTime}");
} }
@@ -516,9 +476,31 @@ namespace Marro.PacManUdon
} }
} }
private SyncedObject[] GetEventSubscribers(NetworkEventType eventType) => private SyncedObject[] GetEventSubscribers(NetworkEventType eventType) => networkEventSubscribers[(int)eventType];
//networkEventSubscribers[(int)eventType];
syncedUpdateSubscribers; 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)
{
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 #endregion
#region Sender #region Sender
@@ -576,9 +558,12 @@ namespace Marro.PacManUdon
var subscibers = GetEventSubscribers(eventType); var subscibers = GetEventSubscribers(eventType);
foreach (var obj in subscibers) 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 // Validate and fill in event size
@@ -862,22 +847,27 @@ namespace Marro.PacManUdon
ProgressSyncedTime(timestamp); ProgressSyncedTime(timestamp);
var subscibers = GetEventSubscribers(eventType); var subscribers = GetEventSubscribers(eventType);
foreach (var obj in subscibers) Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) ApplyEvent with dt {SyncedDeltaTime}");
if (subscribers != null)
{ {
obj.SyncedUpdate(); foreach (var obj in subscribers)
}
foreach (var obj in subscibers)
{
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}!"); obj.SyncedUpdate();
HandleError(true); }
return false;
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;
}
} }
} }

View File

@@ -50,6 +50,8 @@ namespace Marro.PacManUdon
hideUntilUnfrozen = false; hideUntilUnfrozen = false;
startPosition = startTransform.localPosition; startPosition = startTransform.localPosition;
startRotation = startTransform.localRotation; startRotation = startTransform.localRotation;
SubscribeToEvent(NetworkEventType.PacManTurn);
} }
public void Reset() public void Reset()

View File

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

View File

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