From 5e1ea708183e6c648e305e9ce120c1decab8b0cf Mon Sep 17 00:00:00 2001 From: Natan Date: Sun, 27 Apr 2025 16:13:00 -0300 Subject: [PATCH 1/4] feat: timer state --- .../inventoryframework/ViewConfigBuilder.java | 15 ++++++ .../internal/ElementFactory.java | 3 ++ .../inventoryframework/state/StateAccess.java | 13 +++++ .../inventoryframework/state/TimerState.java | 6 +++ .../state/StateAccessImpl.java | 47 +++++++++++-------- 5 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/TimerState.java diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/ViewConfigBuilder.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/ViewConfigBuilder.java index 930cae428..8f3c58c2e 100644 --- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/ViewConfigBuilder.java +++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/ViewConfigBuilder.java @@ -8,6 +8,7 @@ import java.util.Set; import java.util.stream.Collectors; import me.devnatan.inventoryframework.exception.InvalidLayoutException; +import me.devnatan.inventoryframework.state.TimerState; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -31,6 +32,7 @@ public final class ViewConfigBuilder { private String[] layout = null; private final Set modifiers = new HashSet<>(); private long updateIntervalInTicks, interactionDelayInMillis; + private TimerState updateIntervalState; private boolean transitiveInitialData; /** @@ -200,6 +202,19 @@ public ViewConfigBuilder scheduleUpdate(long intervalInTicks) { return this; } + /** + * Schedules the view to update every fixed interval. + * + * @param timerState The + * @return This configuration builder. + * @see Scheduled Updates on Wiki + */ + @ApiStatus.Experimental + public ViewConfigBuilder scheduleUpdate(TimerState timerState) { + this.updateIntervalState = timerState; + return this; + } + /** * Waits a fixed delay before any player interaction. *

diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/internal/ElementFactory.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/internal/ElementFactory.java index 6bde3f53e..44b8a690e 100644 --- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/internal/ElementFactory.java +++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/internal/ElementFactory.java @@ -17,6 +17,7 @@ import me.devnatan.inventoryframework.context.IFSlotClickContext; import me.devnatan.inventoryframework.context.IFSlotRenderContext; import me.devnatan.inventoryframework.logging.Logger; +import me.devnatan.inventoryframework.state.TimerState; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -88,4 +89,6 @@ public abstract IFSlotRenderContext createSlotRenderContext( public abstract boolean worksInCurrentPlatform(); public abstract Job scheduleJobInterval(@NotNull RootView root, long intervalInTicks, @NotNull Runnable execution); + + public abstract TimerState createTimerState(long stateId, long intervalInTicks); } 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..5902e8b80 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 @@ -173,6 +173,19 @@ public interface StateAccess< */ MutableState initialState(@NotNull String key); + /** + * Creates a new unmodifiable timer state. + * + * @param intervalInTicks Ticks to schedule the timer to run. + *

+ * 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. + * + * @return A new unmodifiable timer state. + */ + @ApiStatus.Experimental + TimerState timerState(long intervalInTicks); + /** * Creates a new immutable pagination with static data source. * diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/TimerState.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/TimerState.java new file mode 100644 index 000000000..b76e4a1ba --- /dev/null +++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/TimerState.java @@ -0,0 +1,6 @@ +package me.devnatan.inventoryframework.state; + +public interface TimerState extends State { + + interface Timer {} +} diff --git a/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/state/StateAccessImpl.java b/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/state/StateAccessImpl.java index 40d59f478..9f0f104a8 100644 --- a/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/state/StateAccessImpl.java +++ b/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/state/StateAccessImpl.java @@ -38,7 +38,7 @@ public StateAccessImpl(Object caller, ElementFactory elementFactory, StateRegist } @Override - public final State state(T initialValue) { + public State state(T initialValue) { final long id = State.next(); final StateValueFactory factory = (host, state) -> new ImmutableValue(state, initialValue); final State state = new BaseState<>(id, factory); @@ -48,7 +48,7 @@ public final State state(T initialValue) { } @Override - public final MutableState mutableState(T initialValue) { + public MutableState mutableState(T initialValue) { final long id = State.next(); final StateValueFactory factory = (host, state) -> new MutableValue(state, initialValue); final MutableState state = new MutableGenericStateImpl<>(id, factory); @@ -58,7 +58,7 @@ public final MutableState mutableState(T initialValue) { } @Override - public final MutableIntState mutableState(int initialValue) { + public MutableIntState mutableState(int initialValue) { final long id = State.next(); final StateValueFactory factory = (host, state) -> new MutableValue(state, initialValue); final MutableIntState state = new MutableIntStateImpl(id, factory); @@ -68,7 +68,7 @@ public final MutableIntState mutableState(int initialValue) { } @Override - public final State computedState(@NotNull Function computation) { + public State computedState(@NotNull Function computation) { final long id = State.next(); @SuppressWarnings("unchecked") final StateValueFactory factory = @@ -80,7 +80,7 @@ public final State computedState(@NotNull Function computatio } @Override - public final State computedState(@NotNull Supplier computation) { + public State computedState(@NotNull Supplier computation) { final long id = State.next(); final StateValueFactory factory = (host, state) -> new ComputedValue(state, computation); final State state = new BaseState<>(id, factory); @@ -90,7 +90,7 @@ public final State computedState(@NotNull Supplier computation) { } @Override - public final State lazyState(@NotNull Function computation) { + public State lazyState(@NotNull Function computation) { final long id = State.next(); @SuppressWarnings("unchecked") final StateValueFactory factory = @@ -102,7 +102,7 @@ public final State lazyState(@NotNull Function computation) { } @Override - public final State lazyState(@NotNull Supplier computation) { + public State lazyState(@NotNull Supplier computation) { final long id = State.next(); final StateValueFactory factory = (host, state) -> new LazyValue(state, computation); final State state = new BaseState<>(id, factory); @@ -113,13 +113,13 @@ public final State lazyState(@NotNull Supplier computation) { @SuppressWarnings("DataFlowIssue") @Override - public final MutableState initialState() { + public MutableState initialState() { return initialState(null); } @SuppressWarnings("NullableProblems") @Override - public final MutableState initialState(@NotNull String key) { + public MutableState initialState(@NotNull String key) { final long id = State.next(); final MutableState state = new BaseMutableState<>(id, (host, valueState) -> new InitialDataStateValue(valueState, host, key)); @@ -129,7 +129,14 @@ public final MutableState initialState(@NotNull String key) { } @Override - public final State paginationState( + public TimerState timerState(long intervalInTicks) { + final TimerState state = elementFactory.createTimerState(State.next(), intervalInTicks); + this.stateRegistry.registerState(state, this); + return state; + } + + @Override + public State paginationState( @NotNull List sourceProvider, @NotNull PaginationValueConsumer elementConsumer) { return this.buildPaginationState(sourceProvider) @@ -138,7 +145,7 @@ public final State paginationState( } @Override - public final State computedPaginationState( + public State computedPaginationState( @NotNull Function> sourceProvider, @NotNull PaginationValueConsumer valueConsumer) { return this.buildComputedPaginationState(sourceProvider) @@ -147,7 +154,7 @@ public final State computedPaginationState( } @Override - public final State computedAsyncPaginationState( + public State computedAsyncPaginationState( @NotNull Function>> sourceProvider, @NotNull PaginationValueConsumer valueConsumer) { return this.buildComputedAsyncPaginationState(sourceProvider) @@ -156,7 +163,7 @@ public final State computedAsyncPaginationState( } @Override - public final State lazyPaginationState( + public State lazyPaginationState( @NotNull Function> sourceProvider, @NotNull PaginationValueConsumer valueConsumer) { return this.buildLazyPaginationState(sourceProvider) @@ -183,48 +190,48 @@ public State lazyAsyncPaginationState( } @Override - public final PaginationStateBuilder buildPaginationState( + public PaginationStateBuilder buildPaginationState( @NotNull List sourceProvider) { return new PaginationStateBuilder<>( this.elementFactory, sourceProvider, this::createPaginationState, false, false); } @Override - public final PaginationStateBuilder buildComputedPaginationState( + public PaginationStateBuilder buildComputedPaginationState( @NotNull Function> sourceProvider) { return new PaginationStateBuilder<>( this.elementFactory, sourceProvider, this::createPaginationState, false, true); } @Override - public final PaginationStateBuilder buildComputedAsyncPaginationState( + public PaginationStateBuilder buildComputedAsyncPaginationState( @NotNull Function>> sourceProvider) { return new PaginationStateBuilder<>( this.elementFactory, sourceProvider, this::createPaginationState, true, true); } @Override - public final PaginationStateBuilder buildLazyPaginationState( + public PaginationStateBuilder buildLazyPaginationState( @NotNull Supplier> sourceProvider) { return new PaginationStateBuilder<>( this.elementFactory, sourceProvider, this::createPaginationState, false, false); } @Override - public final PaginationStateBuilder buildLazyPaginationState( + public PaginationStateBuilder buildLazyPaginationState( @NotNull Function> sourceProvider) { return new PaginationStateBuilder<>( this.elementFactory, sourceProvider, this::createPaginationState, false, false); } @Override - public final PaginationStateBuilder buildLazyAsyncPaginationState( + public PaginationStateBuilder buildLazyAsyncPaginationState( @NotNull Function>> sourceProvider) { return new PaginationStateBuilder<>( this.elementFactory, sourceProvider, this::createPaginationState, true, false); } - protected final State createPaginationState( + private State createPaginationState( @NotNull PaginationStateBuilder builder) { final long id = State.next(); @SuppressWarnings({"unchecked", "rawtypes"}) From 65a3f1067e2b5739a861d4cf8ad6853533152b3a Mon Sep 17 00:00:00 2001 From: Natan Date: Sun, 27 Apr 2025 16:29:22 -0300 Subject: [PATCH 2/4] feat: update samples --- .../runtime/command/IFExampleCommand.kt | 2 + .../runtime/view/ScheduledViewAdvanced.kt | 36 +++++++++++++++++ .../runtime/SamplePlugin.java | 8 +++- .../commands/IFExampleCommandExecutor.java | 10 +++-- .../runtime/view/AutoUpdateAdvanced.java | 39 +++++++++++++++++++ .../inventoryframework/state/TimerState.java | 11 +++++- .../inventoryframework/state/StateAccess.kt | 5 +++ .../inventoryframework/PlatformView.java | 14 +++---- 8 files changed, 112 insertions(+), 13 deletions(-) create mode 100644 examples/minestom/src/main/kotlin/me/devnatan/inventoryframework/runtime/view/ScheduledViewAdvanced.kt create mode 100644 examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/view/AutoUpdateAdvanced.java create mode 100644 inventory-framework-api/src/main/kotlin/me/devnatan/inventoryframework/state/StateAccess.kt diff --git a/examples/minestom/src/main/kotlin/me/devnatan/inventoryframework/runtime/command/IFExampleCommand.kt b/examples/minestom/src/main/kotlin/me/devnatan/inventoryframework/runtime/command/IFExampleCommand.kt index be5bd477c..e81a44933 100644 --- a/examples/minestom/src/main/kotlin/me/devnatan/inventoryframework/runtime/command/IFExampleCommand.kt +++ b/examples/minestom/src/main/kotlin/me/devnatan/inventoryframework/runtime/command/IFExampleCommand.kt @@ -3,6 +3,7 @@ package me.devnatan.inventoryframework.runtime.command import me.devnatan.inventoryframework.ViewFrame import me.devnatan.inventoryframework.runtime.view.Failing import me.devnatan.inventoryframework.runtime.view.ScheduledView +import me.devnatan.inventoryframework.runtime.view.ScheduledViewAdvanced import me.devnatan.inventoryframework.runtime.view.SimplePagination import net.minestom.server.command.CommandSender import net.minestom.server.command.builder.Command @@ -20,6 +21,7 @@ class IFExampleCommand( "failing" to Failing::class.java, "simple-pagination" to SimplePagination::class.java, "scheduled" to ScheduledView::class.java, + "scheduled-advanced" to ScheduledViewAdvanced::class.java, ) private val arg: Argument = diff --git a/examples/minestom/src/main/kotlin/me/devnatan/inventoryframework/runtime/view/ScheduledViewAdvanced.kt b/examples/minestom/src/main/kotlin/me/devnatan/inventoryframework/runtime/view/ScheduledViewAdvanced.kt new file mode 100644 index 000000000..9a54e188f --- /dev/null +++ b/examples/minestom/src/main/kotlin/me/devnatan/inventoryframework/runtime/view/ScheduledViewAdvanced.kt @@ -0,0 +1,36 @@ +package me.devnatan.inventoryframework.runtime.view + +import me.devnatan.inventoryframework.View +import me.devnatan.inventoryframework.ViewConfigBuilder +import me.devnatan.inventoryframework.context.Context +import me.devnatan.inventoryframework.context.RenderContext +import me.devnatan.inventoryframework.context.SlotClickContext +import me.devnatan.inventoryframework.runtime.ExampleUtil +import me.devnatan.inventoryframework.state.timerState +import net.minestom.server.item.Material +import kotlin.time.Duration.Companion.seconds + +class ScheduledViewAdvanced : View() { + val counter = mutableState(0) + val timer = timerState(1.seconds) + + override fun onInit(config: ViewConfigBuilder): Unit = + with(config) { + cancelOnClick() + size(3) + title("Simple Pagination") + layout(" ", " C ", "B ") + scheduleUpdate(timer) + } + + override fun onFirstRender(render: RenderContext) { + render.layoutSlot('C').onRender { + it.item = ExampleUtil.displayItem(Material.STONE, counter.increment(it).toString()) + } + + render + .layoutSlot('B', ExampleUtil.displayItem(Material.PAPER, "Back")) + .displayIf(Context::canBack) + .onClick(SlotClickContext::back) + } +} diff --git a/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/SamplePlugin.java b/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/SamplePlugin.java index 409640222..811a3ce79 100644 --- a/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/SamplePlugin.java +++ b/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/SamplePlugin.java @@ -8,6 +8,7 @@ import me.devnatan.inventoryframework.runtime.view.AutoUpdate; import me.devnatan.inventoryframework.runtime.view.Failing; import me.devnatan.inventoryframework.runtime.view.SimplePagination; +import me.devnatan.inventoryframework.runtime.view.*; import org.bukkit.plugin.java.JavaPlugin; public class SamplePlugin extends JavaPlugin { @@ -17,7 +18,12 @@ public void onEnable() { System.out.println("ligoo"); ViewFrame viewFrame = ViewFrame.create(this) .install(AnvilInputFeature.AnvilInput) - .with(new AnvilInputSample(), new Failing(), new SimplePagination(), new AutoUpdate()) + .with( + new AnvilInputSample(), + new Failing(), + new SimplePagination(), + new AutoUpdate(), + new AutoUpdateAdvanced()) .register(); getCommand("ifexample").setExecutor(new IFExampleCommandExecutor(viewFrame)); diff --git a/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/commands/IFExampleCommandExecutor.java b/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/commands/IFExampleCommandExecutor.java index 4faf686c7..61d653c01 100644 --- a/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/commands/IFExampleCommandExecutor.java +++ b/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/commands/IFExampleCommandExecutor.java @@ -1,10 +1,7 @@ package me.devnatan.inventoryframework.runtime.commands; import me.devnatan.inventoryframework.ViewFrame; -import me.devnatan.inventoryframework.runtime.view.AnvilInputSample; -import me.devnatan.inventoryframework.runtime.view.AutoUpdate; -import me.devnatan.inventoryframework.runtime.view.Failing; -import me.devnatan.inventoryframework.runtime.view.SimplePagination; +import me.devnatan.inventoryframework.runtime.view.*; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; @@ -60,6 +57,11 @@ public boolean onCommand( return true; } + if (view.equalsIgnoreCase("auto-update-advanced")) { + viewFrame.open(AutoUpdateAdvanced.class, player); + return true; + } + commandSender.sendMessage("Unknown view: " + view); return true; } diff --git a/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/view/AutoUpdateAdvanced.java b/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/view/AutoUpdateAdvanced.java new file mode 100644 index 000000000..add95fb14 --- /dev/null +++ b/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/view/AutoUpdateAdvanced.java @@ -0,0 +1,39 @@ +package me.devnatan.inventoryframework.runtime.view; + +import me.devnatan.inventoryframework.View; +import me.devnatan.inventoryframework.ViewConfigBuilder; +import me.devnatan.inventoryframework.context.Context; +import me.devnatan.inventoryframework.context.RenderContext; +import me.devnatan.inventoryframework.state.MutableIntState; +import me.devnatan.inventoryframework.state.TimerState; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +public class AutoUpdateAdvanced extends View { + + private final MutableIntState countState = mutableState(0); + private final TimerState autoUpdateState = timerState(10); + + @Override + public void onInit(@NotNull ViewConfigBuilder config) { + config.cancelOnClick().title("Auto update (?)").scheduleUpdate(autoUpdateState); + } + + @Override + public void onFirstRender(@NotNull RenderContext render) { + render.slot(1, new ItemStack(Material.DIAMOND)).onClick(click -> click.openForPlayer(SimplePagination.class)); + + render.slot(2, new ItemStack(Material.CLOCK)).onClick(click -> { + final var timer = autoUpdateState.get(click); + timer.togglePause(); + }); + } + + @Override + public void onUpdate(@NotNull Context update) { + final int count = countState.increment(update); + final String pause = autoUpdateState.get(update).isPaused() ? "paused" : "running"; + update.updateTitleForPlayer(String.format("Auto update (%d) [%b]", count, pause)); + } +} diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/TimerState.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/TimerState.java index b76e4a1ba..7792eb8a5 100644 --- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/TimerState.java +++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/state/TimerState.java @@ -2,5 +2,14 @@ public interface TimerState extends State { - interface Timer {} + interface Timer { + + long initialInterval(); + + long currentInterval(); + + boolean isPaused(); + + boolean togglePause(); + } } diff --git a/inventory-framework-api/src/main/kotlin/me/devnatan/inventoryframework/state/StateAccess.kt b/inventory-framework-api/src/main/kotlin/me/devnatan/inventoryframework/state/StateAccess.kt new file mode 100644 index 000000000..145d88c7d --- /dev/null +++ b/inventory-framework-api/src/main/kotlin/me/devnatan/inventoryframework/state/StateAccess.kt @@ -0,0 +1,5 @@ +package me.devnatan.inventoryframework.state + +import kotlin.time.Duration + +public fun StateAccess<*, *>.timerState(interval: Duration): TimerState = timerState(interval.inWholeSeconds / 20) 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 47e197b33..8b5d60942 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 @@ -39,13 +39,7 @@ import me.devnatan.inventoryframework.pipeline.StandardPipelinePhases; import me.devnatan.inventoryframework.pipeline.UpdateInterceptor; import me.devnatan.inventoryframework.pipeline.ViewerLastInteractionTrackerInterceptor; -import me.devnatan.inventoryframework.state.InitialDataStateValue; -import me.devnatan.inventoryframework.state.MutableIntState; -import me.devnatan.inventoryframework.state.MutableState; -import me.devnatan.inventoryframework.state.State; -import me.devnatan.inventoryframework.state.StateAccess; -import me.devnatan.inventoryframework.state.StateAccessImpl; -import me.devnatan.inventoryframework.state.StateValue; +import me.devnatan.inventoryframework.state.*; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -765,5 +759,11 @@ public final PaginationStateBuilder buildLazyAsyncPagina requireNotInitialized(); return stateAccess.buildLazyAsyncPaginationState(sourceProvider); } + + @Override + public TimerState timerState(long intervalInTicks) { + requireNotInitialized(); + return stateAccess.timerState(intervalInTicks); + } // endregion } From 68fa239d524f41fadd13a2863d7a758dea5595c7 Mon Sep 17 00:00:00 2001 From: Natan Date: Mon, 30 Jun 2025 15:30:56 -0300 Subject: [PATCH 3/4] chore: add folialib dependency --- gradle/libs.versions.toml | 5 +++++ inventory-framework-platform-paper/build.gradle.kts | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 933431be2..85fa8f8ca 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,6 +13,7 @@ plugin-shadowjar = "8.3.7" plugin-spotless = "7.0.4" plugin-bukkit = "0.7.1" minestom = "b39badc77b" +folialib = "0.5.1" [libraries.spigot] module = "org.spigotmc:spigot-api" @@ -52,6 +53,10 @@ version.ref = "adventure-api" module = "net.minestom:minestom-snapshots" version.ref = "minestom" +[libraries.folialib] +module = "com.tcoded:FoliaLib" +version.ref = "folialib" + [plugins] shadowjar = { id = "com.gradleup.shadow", version.ref = "plugin-shadowjar" } spotless = { id = "com.diffplug.spotless", version.ref = "plugin-spotless" } diff --git a/inventory-framework-platform-paper/build.gradle.kts b/inventory-framework-platform-paper/build.gradle.kts index 8c4131015..25880df0f 100644 --- a/inventory-framework-platform-paper/build.gradle.kts +++ b/inventory-framework-platform-paper/build.gradle.kts @@ -7,9 +7,14 @@ inventoryFramework { publish = true } +repositories { + maven("https://repo.tcoded.com/releases") +} + dependencies { compileOnly(libs.paperSpigot) implementation(projects.inventoryFrameworkPlatformBukkit) + implementation(libs.folialib) } java { From 85620b6bc37b79fe4a8f1ce9656e1cfa3e053121 Mon Sep 17 00:00:00 2001 From: Natan Date: Sat, 19 Jul 2025 15:54:31 -0300 Subject: [PATCH 4/4] feat: use folialib --- .../runtime/SamplePlugin.java | 2 +- .../context/IFSlotClickContext.java | 190 +++++++++--------- .../build.gradle.kts | 1 + .../inventoryframework/ViewFrame.java | 5 +- .../internal/BukkitElementFactory.java | 17 +- .../internal/BukkitTaskJobImpl.java | 16 +- .../inventoryframework/IFInventoryListener.kt | 5 +- .../context/SlotClickContext.kt | 3 +- .../internal/MinestomElementFactory.kt | 6 +- .../build.gradle.kts | 1 - 10 files changed, 128 insertions(+), 118 deletions(-) diff --git a/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/SamplePlugin.java b/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/SamplePlugin.java index 811a3ce79..6611a0019 100644 --- a/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/SamplePlugin.java +++ b/examples/paper/src/main/java/me/devnatan/inventoryframework/runtime/SamplePlugin.java @@ -4,11 +4,11 @@ import me.devnatan.inventoryframework.ViewFrame; import me.devnatan.inventoryframework.runtime.commands.IFExampleCommandExecutor; import me.devnatan.inventoryframework.runtime.listener.PigListener; +import me.devnatan.inventoryframework.runtime.view.*; import me.devnatan.inventoryframework.runtime.view.AnvilInputSample; import me.devnatan.inventoryframework.runtime.view.AutoUpdate; import me.devnatan.inventoryframework.runtime.view.Failing; import me.devnatan.inventoryframework.runtime.view.SimplePagination; -import me.devnatan.inventoryframework.runtime.view.*; import org.bukkit.plugin.java.JavaPlugin; public class SamplePlugin extends JavaPlugin { diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFSlotClickContext.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFSlotClickContext.java index befa35c66..78a390b63 100644 --- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFSlotClickContext.java +++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFSlotClickContext.java @@ -13,99 +13,99 @@ */ public interface IFSlotClickContext extends IFSlotContext, IFConfinedContext { - // TODO needs documentation - @NotNull - ViewContainer getClickedContainer(); - - Component getComponent(); - - int getClickedSlot(); - - /** - * If the click was using the left mouse button. - * - * @return If the click was using the left mouse button. - */ - boolean isLeftClick(); - - /** - * If the click was using the right mouse button. - * - * @return If the click was using the right mouse button. - */ - boolean isRightClick(); - - /** - * If the click was using the middle mouse button, commonly known as the scroll button. - * - * @return If the click was using the middle mouse button. - */ - boolean isMiddleClick(); - - /** - * If the click was accompanied by a click holding the keyboard shift button. - * - * @return If it was a click holding the keyboard shift button. - */ - boolean isShiftClick(); - - default boolean isShiftLeftClick() { - return isLeftClick() && isShiftClick(); - } - - default boolean isShiftRightClick() { - return isRightClick() && isShiftClick(); - } - - /** - * If the click source came from a keyboard, e.g. the player's toolbar number. - * - * @return If the click source came from a keyboard. - */ - boolean isKeyboardClick(); - - /** - * If the click did not occur within any containers. - * - * @return If the click did not occur within any containers. - */ - boolean isOutsideClick(); - - /** - * The click identifier, available only in cases where the library does not cover all types of - * clicks, so you can discover the type of click through its identifier. - * - * @return The click type identifier. Can be null if the click type is known or a platform doesn't implement an identifier. - */ - default String getClickIdentifier() { - return null; - } - - /** - * If the click was cancelled. - * - * @return If the click was cancelled. - */ - boolean isCancelled(); - - /** - * Cancels the click. - * - * @param cancelled If the click should be cancelled. - */ - void setCancelled(boolean cancelled); - - /** - * This is an internal inventory-framework API that should not be used from outside of - * this library. No compatibility guarantees are provided. - */ - @ApiStatus.Internal - Object getPlatformEvent(); - - /** - * This is an internal inventory-framework API that should not be used from outside of - * this library. No compatibility guarantees are provided. - */ - @ApiStatus.Internal - boolean isCombined(); + // TODO needs documentation + @NotNull + ViewContainer getClickedContainer(); + + Component getComponent(); + + int getClickedSlot(); + + /** + * If the click was using the left mouse button. + * + * @return If the click was using the left mouse button. + */ + boolean isLeftClick(); + + /** + * If the click was using the right mouse button. + * + * @return If the click was using the right mouse button. + */ + boolean isRightClick(); + + /** + * If the click was using the middle mouse button, commonly known as the scroll button. + * + * @return If the click was using the middle mouse button. + */ + boolean isMiddleClick(); + + /** + * If the click was accompanied by a click holding the keyboard shift button. + * + * @return If it was a click holding the keyboard shift button. + */ + boolean isShiftClick(); + + default boolean isShiftLeftClick() { + return isLeftClick() && isShiftClick(); + } + + default boolean isShiftRightClick() { + return isRightClick() && isShiftClick(); + } + + /** + * If the click source came from a keyboard, e.g. the player's toolbar number. + * + * @return If the click source came from a keyboard. + */ + boolean isKeyboardClick(); + + /** + * If the click did not occur within any containers. + * + * @return If the click did not occur within any containers. + */ + boolean isOutsideClick(); + + /** + * The click identifier, available only in cases where the library does not cover all types of + * clicks, so you can discover the type of click through its identifier. + * + * @return The click type identifier. Can be null if the click type is known or a platform doesn't implement an identifier. + */ + default String getClickIdentifier() { + return null; + } + + /** + * If the click was cancelled. + * + * @return If the click was cancelled. + */ + boolean isCancelled(); + + /** + * Cancels the click. + * + * @param cancelled If the click should be cancelled. + */ + void setCancelled(boolean cancelled); + + /** + * This is an internal inventory-framework API that should not be used from outside of + * this library. No compatibility guarantees are provided. + */ + @ApiStatus.Internal + Object getPlatformEvent(); + + /** + * This is an internal inventory-framework API that should not be used from outside of + * this library. No compatibility guarantees are provided. + */ + @ApiStatus.Internal + boolean isCombined(); } diff --git a/inventory-framework-platform-bukkit/build.gradle.kts b/inventory-framework-platform-bukkit/build.gradle.kts index 611ada158..dd377a455 100644 --- a/inventory-framework-platform-bukkit/build.gradle.kts +++ b/inventory-framework-platform-bukkit/build.gradle.kts @@ -17,6 +17,7 @@ dependencies { testRuntimeOnly(libs.spigot) testImplementation(projects.inventoryFrameworkApi) testImplementation(projects.inventoryFrameworkTest) + implementation(libs.folialib) } tasks.shadowJar { diff --git a/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/ViewFrame.java b/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/ViewFrame.java index 632dae721..ffc02ff43 100644 --- a/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/ViewFrame.java +++ b/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/ViewFrame.java @@ -38,10 +38,6 @@ public class ViewFrame extends IFViewFrame { private final Plugin owner; private final FeatureInstaller featureInstaller = new DefaultFeatureInstaller<>(this); - static { - PlatformUtils.setFactory(new BukkitElementFactory()); - } - private ViewFrame(Plugin owner) { this.owner = owner; } @@ -191,6 +187,7 @@ public final void openEndless( public final ViewFrame register() { if (isRegistered()) throw new IllegalStateException("This view frame is already registered"); + PlatformUtils.setFactory(new BukkitElementFactory(getOwner())); tryEnableMetrics(); checkRelocationIssues(); setRegistered(true); diff --git a/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/internal/BukkitElementFactory.java b/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/internal/BukkitElementFactory.java index 59e101a72..a19a246f8 100644 --- a/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/internal/BukkitElementFactory.java +++ b/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/internal/BukkitElementFactory.java @@ -2,6 +2,7 @@ import static me.devnatan.inventoryframework.runtime.util.InventoryUtils.checkInventoryTypeSupport; +import com.tcoded.folialib.FoliaLib; import java.util.List; import java.util.Map; import java.util.UUID; @@ -14,10 +15,12 @@ import me.devnatan.inventoryframework.context.*; import me.devnatan.inventoryframework.logging.Logger; import me.devnatan.inventoryframework.logging.NoopLogger; +import me.devnatan.inventoryframework.state.TimerState; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; +import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,6 +29,12 @@ public class BukkitElementFactory extends ElementFactory { private static final ViewType defaultType = ViewType.CHEST; private Boolean worksInCurrentPlatform = null; + private final FoliaLib foliaLib; + + public BukkitElementFactory(Plugin plugin) { + this.foliaLib = new FoliaLib(plugin); + } + @Override public @NotNull RootView createUninitializedRoot() { return new View(); @@ -142,6 +151,12 @@ public Logger getLogger() { @Override public Job scheduleJobInterval(@NotNull RootView root, long intervalInTicks, @NotNull Runnable execution) { - return new BukkitTaskJobImpl(((View) root).getFramework().getOwner(), intervalInTicks, execution); + return new BukkitTaskJobImpl(foliaLib.getScheduler(), intervalInTicks, execution); + } + + @Override + public TimerState createTimerState(long stateId, long intervalInTicks) { + + return null; } } diff --git a/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/internal/BukkitTaskJobImpl.java b/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/internal/BukkitTaskJobImpl.java index 67f5c92e1..3b15cef6c 100644 --- a/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/internal/BukkitTaskJobImpl.java +++ b/inventory-framework-platform-bukkit/src/main/java/me/devnatan/inventoryframework/internal/BukkitTaskJobImpl.java @@ -1,30 +1,30 @@ package me.devnatan.inventoryframework.internal; -import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitTask; +import com.tcoded.folialib.impl.PlatformScheduler; +import com.tcoded.folialib.wrapper.task.WrappedTask; class BukkitTaskJobImpl implements Job { - private final Plugin plugin; + private final PlatformScheduler scheduler; private final long intervalInTicks; private final Runnable execution; - private BukkitTask task; + private WrappedTask task; - public BukkitTaskJobImpl(Plugin plugin, long intervalInTicks, Runnable execution) { - this.plugin = plugin; + public BukkitTaskJobImpl(PlatformScheduler scheduler, long intervalInTicks, Runnable execution) { + this.scheduler = scheduler; this.intervalInTicks = intervalInTicks; this.execution = execution; } @Override public boolean isStarted() { - return task != null; + return task != null && !task.isCancelled(); } @Override public void start() { if (isStarted()) return; - task = plugin.getServer().getScheduler().runTaskTimer(plugin, this::loop, intervalInTicks, intervalInTicks); + task = scheduler.runTimer(this::loop, intervalInTicks, intervalInTicks); } @Override diff --git a/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/IFInventoryListener.kt b/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/IFInventoryListener.kt index ba39cbd9d..5155045bc 100644 --- a/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/IFInventoryListener.kt +++ b/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/IFInventoryListener.kt @@ -45,10 +45,7 @@ internal class IFInventoryListener( event.isCancelled = context.config.getOptionValue(ViewConfig.CANCEL_ON_DROP) return } - if ( - event.click is Click.LeftDrag || - event.click is Click.RightDrag - ) { + if (event.click is Click.LeftDrag || event.click is Click.RightDrag) { val context: IFContext = viewer.activeContext if (!context.config.isOptionSet(ViewConfig.CANCEL_ON_DRAG)) return diff --git a/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/context/SlotClickContext.kt b/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/context/SlotClickContext.kt index d827082c0..e5b86014b 100644 --- a/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/context/SlotClickContext.kt +++ b/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/context/SlotClickContext.kt @@ -64,8 +64,7 @@ class SlotClickContext override fun isShiftClick(): Boolean { val clickType = clickOrigin.click - return clickType is Click.LeftShift || - clickType is Click.RightShift + return clickType is Click.LeftShift || clickType is Click.RightShift } override fun isKeyboardClick(): Boolean = clickOrigin.click is Click.HotbarSwap diff --git a/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/internal/MinestomElementFactory.kt b/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/internal/MinestomElementFactory.kt index fa0a1c1c0..1734ee40e 100644 --- a/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/internal/MinestomElementFactory.kt +++ b/inventory-framework-platform-minestom/src/main/kotlin/me/devnatan/inventoryframework/internal/MinestomElementFactory.kt @@ -91,9 +91,11 @@ class MinestomElementFactory : ElementFactory() { type, when (val title = config.title) { is net.kyori.adventure.text.Component -> title - null -> net.kyori.adventure.text.Component.empty() + null -> + net.kyori.adventure.text.Component + .empty() else -> text(title.toString()) - } + }, ) return MinestomViewContainer(inventory, false, finalType, false) } diff --git a/inventory-framework-platform-paper/build.gradle.kts b/inventory-framework-platform-paper/build.gradle.kts index 25880df0f..0f7247090 100644 --- a/inventory-framework-platform-paper/build.gradle.kts +++ b/inventory-framework-platform-paper/build.gradle.kts @@ -14,7 +14,6 @@ repositories { dependencies { compileOnly(libs.paperSpigot) implementation(projects.inventoryFrameworkPlatformBukkit) - implementation(libs.folialib) } java {