From 4d21ca8d76baefedefad6aeda5357794f61bc66c Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 28 Jun 2026 08:48:34 +0100 Subject: [PATCH] Use reactive catalog for action bar bindings --- Aetheria.State.Verify/Program.cs | 27 +++++++++++++++++++ Assets/Scripts/Gameplay/ActionBarSlot.cs | 26 ++++++++++++++---- .../Runtime/AetheriaClientState.cs | 12 +++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 1c5652b95..c9c8c74df 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -6978,6 +6978,8 @@ static void RequireUnitySharedDocumentAccessorErgonomics(string root) var requiredClientSymbols = new[] { "public AetheriaRuntimeCatalogSnapshot LatestCatalog()", + "public Task> ReactiveCatalogAsync(", + "public CultMeshReactiveDocument ReactiveCatalog(", "public Task LatestPlayerAsync()", "public AetheriaRuntimePlayerSettingsDocument LatestPlayer()", "public Task> ReactivePlayerAsync(", @@ -7047,6 +7049,31 @@ static void RequireUnitySharedDocumentAccessorErgonomics(string root) string.Join(", ", offenders)); } + var actionBarSlot = File.ReadAllText(Path.Combine( + root, + "Assets", + "Scripts", + "Gameplay", + "ActionBarSlot.cs")); + var requiredActionBarSymbols = new[] + { + "public abstract class ActionBarBinding : IDisposable", + "CultMeshReactiveDocument _catalog", + "Client.Aetheria().ReactiveCatalog()", + "_catalog?.Current?.FindItem(item.ItemKey)", + "binding?.Dispose()", + "private void OnDestroy()" + }; + var missingActionBarSymbols = requiredActionBarSymbols + .Where(symbol => !actionBarSlot.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + if (missingActionBarSymbols.Length > 0) + { + throw new InvalidOperationException( + "ActionBarSlot should resolve runtime catalog items through a managed reactive catalog document with binding lifetime disposal: " + + string.Join(", ", missingActionBarSymbols)); + } + var volumeCloudRenderer = File.ReadAllText(Path.Combine( root, "Assets", diff --git a/Assets/Scripts/Gameplay/ActionBarSlot.cs b/Assets/Scripts/Gameplay/ActionBarSlot.cs index c5226469d..8cd8c6e1a 100644 --- a/Assets/Scripts/Gameplay/ActionBarSlot.cs +++ b/Assets/Scripts/Gameplay/ActionBarSlot.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using GameCult.Aetheria.State.Verse; +using GameCult.Mesh; using TMPro; using UniRx.Triggers; using UnityEngine; @@ -24,6 +25,10 @@ public class ActionBarSlot : MonoBehaviour get => binding; set { + if (ReferenceEquals(binding, value)) + return; + + binding?.Dispose(); binding = value; if (binding == null) { @@ -35,6 +40,11 @@ public class ActionBarSlot : MonoBehaviour } } + private void OnDestroy() + { + Binding = null; + } + private void Update() { Binding?.Update(); @@ -42,13 +52,13 @@ public class ActionBarSlot : MonoBehaviour } -public abstract class ActionBarBinding +public abstract class ActionBarBinding : IDisposable { public Entity Entity { get; } protected AetheriaClient Client { get; } protected ActionBarSlot Slot { get; } protected GameSettings Settings { get; } - private AetheriaRuntimeCatalogSnapshot _catalog; + private CultMeshReactiveDocument _catalog; public abstract void Activate(); public abstract void Deactivate(); public abstract void Update(); @@ -85,15 +95,21 @@ public abstract class ActionBarBinding try { - _catalog ??= Client.Aetheria().LatestCatalog(); - return _catalog?.FindItem(item.ItemKey); + _catalog ??= Client.Aetheria().ReactiveCatalog(); + return _catalog?.Current?.FindItem(item.ItemKey); } catch (Exception ex) { - Debug.LogWarning($"Failed to read Aetheria runtime catalog for action-bar binding: {ex.Message}"); + Debug.LogWarning($"Failed to bind Aetheria runtime catalog for action-bar binding: {ex.Message}"); return null; } } + + public virtual void Dispose() + { + _catalog?.Dispose(); + _catalog = null; + } } public class ActionBarConsumableBinding : ActionBarBinding diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs index 62cf4bac2..f1719e590 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs @@ -188,6 +188,18 @@ namespace GameCult.Aetheria.State.Verse return Latest(); } + public Task> ReactiveCatalogAsync( + CultMeshReactiveDocumentOptions? options = null) + { + return Catalog.ReactiveAsync(options); + } + + public CultMeshReactiveDocument ReactiveCatalog( + CultMeshReactiveDocumentOptions? options = null) + { + return Catalog.Reactive(options); + } + public Task LatestDaemonFrameAsync() { return LatestFrame.LatestAsync();