From 6d6b0aa7add099f7b4af6025ffa21f2b1db72799 Mon Sep 17 00:00:00 2001 From: Natan Date: Sun, 27 Apr 2025 17:14:21 -0300 Subject: [PATCH 1/2] feat: async state interface & `lazyAsyncState` --- .../inventoryframework/state/AsyncState.java | 3 ++ .../inventoryframework/state/State.java | 9 +++++ .../inventoryframework/state/StateAccess.java | 34 +++++++++++++++++++ .../inventoryframework/PlatformView.java | 12 +++++++ 4 files changed, 58 insertions(+) create mode 100644 inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/AsyncState.java diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/AsyncState.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/AsyncState.java new file mode 100644 index 000000000..0656a600c --- /dev/null +++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/AsyncState.java @@ -0,0 +1,3 @@ +package me.devnatan.inventoryframework.state; + +public interface AsyncState extends State {} diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/State.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/State.java index e210e955e..3578e1bf7 100644 --- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/State.java +++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/State.java @@ -16,6 +16,11 @@ */ public interface State { + /** + *

This is an internal inventory-framework API that should not be used from outside of + * this library. No compatibility guarantees are provided. + */ + @ApiStatus.Internal AtomicLong ids = new AtomicLong(); /** @@ -51,8 +56,12 @@ public interface State { /** * Generates a new state id. * + *

This is an internal inventory-framework API that should not be used from outside of + * this library. No compatibility guarantees are provided. + * * @return A new unique state id. */ + @ApiStatus.Internal static long next() { return ids.getAndIncrement(); } diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/StateAccess.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/StateAccess.java index a9eac47d4..f5f2e1908 100644 --- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/StateAccess.java +++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/StateAccess.java @@ -139,6 +139,40 @@ public interface StateAccess< */ State lazyState(@NotNull Supplier computation); + /** + * Creates an immutable lazy asynchronous state. + *

+ * This method expects you to return a {@link CompletableFuture} in computation + * parameter so elements in the view that are watching that state can hook to it and wait + * until that future gets completed to proceed with whatever they are willing to do. + *

+ * This API is experimental and is not subject to the general compatibility guarantees such API + * may be changed or may be removed completely in any further release. + * + * @param computation The value factory. + * @param The state value type. + * @return A new lazy asynchronous state instance. + */ + @ApiStatus.Experimental + State lazyAsyncState(@NotNull Supplier> computation); + + /** + * Creates an immutable lazy asynchronous state. + *

+ * This method expects you to return a {@link CompletableFuture} in computation + * parameter so elements in the view that are watching that state can hook to it and wait + * until that future gets completed to proceed with whatever they are willing to do. + *

+ * This API is experimental and is not subject to the general compatibility guarantees such API + * may be changed or may be removed completely in any further release. + * + * @param computation The value factory. + * @param The state value type. + * @return A new lazy asynchronous state instance. + */ + @ApiStatus.Experimental + State lazyAsyncState(@NotNull Function> computation); + /** * Creates a mutable {@link #lazyState(Function) lazy state} whose value is always computed * from the initial data set by its {@link StateValueHost}. diff --git a/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PlatformView.java b/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PlatformView.java index 560687c0a..d5f131452 100644 --- a/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PlatformView.java +++ b/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PlatformView.java @@ -664,6 +664,18 @@ public final State lazyState(@NotNull Supplier computation) { return stateAccess.lazyState(computation); } + @Override + public State lazyAsyncState(@NotNull Supplier> computation) { + requireNotInitialized(); + return stateAccess.lazyAsyncState(computation); + } + + @Override + public State lazyAsyncState(@NotNull Function> computation) { + requireNotInitialized(); + return stateAccess.lazyAsyncState(computation); + } + @Override public final MutableState initialState() { requireNotInitialized(); From 375e44a902d3c1990ca0bb7557974c04fbf35d63 Mon Sep 17 00:00:00 2001 From: Natan Date: Sun, 27 Apr 2025 17:14:31 -0300 Subject: [PATCH 2/2] feat: open context `waitFor` --- .../inventoryframework/context/IFOpenContext.java | 13 +++++++++++++ .../inventoryframework/context/OpenContext.java | 7 +++++++ .../inventoryframework/context/OpenContext.kt | 6 ++++++ 3 files changed, 26 insertions(+) diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFOpenContext.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFOpenContext.java index 453641041..8a563da19 100644 --- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFOpenContext.java +++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFOpenContext.java @@ -4,6 +4,7 @@ import me.devnatan.inventoryframework.ViewConfig; import me.devnatan.inventoryframework.ViewConfigBuilder; import me.devnatan.inventoryframework.ViewContainer; +import me.devnatan.inventoryframework.state.AsyncState; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -34,6 +35,18 @@ public interface IFOpenContext extends IFConfinedContext { */ void waitUntil(@NotNull CompletableFuture task); + /** + * Waits for a asynchronous state to be complete before ending this opening context and + * transitioning to the rendering context (waits to show the inventory to the player). + *

+ * This API is experimental and is not subject to the general compatibility guarantees such API + * may be changed or may be removed completely in any further release. + * + * @param state The state to wait before opening the inventory. + */ + @ApiStatus.Experimental + void waitFor(@NotNull AsyncState state); + /** * Whether opening the container to the viewer has been cancelled. * diff --git a/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/context/OpenContext.java b/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/context/OpenContext.java index 54dd03fab..d5c70a312 100644 --- a/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/context/OpenContext.java +++ b/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/context/OpenContext.java @@ -13,6 +13,7 @@ import me.devnatan.inventoryframework.ViewConfigBuilder; import me.devnatan.inventoryframework.ViewContainer; import me.devnatan.inventoryframework.Viewer; +import me.devnatan.inventoryframework.state.AsyncState; import org.bukkit.entity.Player; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -31,6 +32,7 @@ public class OpenContext extends PlatformConfinedContext implements IFOpenContex // --- User Provided --- private CompletableFuture waitTask; + private AsyncState waitState; private ViewConfigBuilder inheritedConfigBuilder; // --- Properties --- @@ -139,6 +141,11 @@ public final void waitUntil(@NotNull CompletableFuture task) { this.waitTask = task; } + @Override + public void waitFor(@NotNull AsyncState state) { + this.waitState = state; + } + @Override public final @NotNull ViewConfig getConfig() { return inheritedConfigBuilder == null diff --git a/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/context/OpenContext.kt b/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/context/OpenContext.kt index 24183f569..97884470e 100644 --- a/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/context/OpenContext.kt +++ b/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/context/OpenContext.kt @@ -6,6 +6,7 @@ import me.devnatan.inventoryframework.ViewConfig import me.devnatan.inventoryframework.ViewConfigBuilder import me.devnatan.inventoryframework.ViewContainer import me.devnatan.inventoryframework.Viewer +import me.devnatan.inventoryframework.state.AsyncState import net.kyori.adventure.text.Component import net.minestom.server.entity.Player import org.jetbrains.annotations.ApiStatus @@ -44,6 +45,7 @@ class OpenContext // --- User Provided --- private var waitTask: CompletableFuture? = null + private var waitState: AsyncState<*>? = null private var inheritedConfigBuilder: ViewConfigBuilder? = null // --- Properties --- @@ -109,6 +111,10 @@ class OpenContext this.waitTask = task } + override fun waitFor(state: AsyncState<*>) { + this.waitState = state + } + override fun getConfig(): ViewConfig = if (inheritedConfigBuilder == null) { getRoot().config