e : ordered) {
- var key = e.getKey();
- var replacement = e.getValue();
-
- var config = TextReplacementConfig.builder()
- .matchLiteral(key)
- .replacement(replacement)
- .build();
-
- out = out.replaceText(config);
- }
+ .toList();
- return out;
+ return input.replaceText(builder -> {
+ for (var entry : ordered) {
+ builder.matchLiteral(entry.getKey()).replacement(entry.getValue());
+ }
+ });
}
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/adventure/AdventurePlaceholders.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/adventure/AdventurePlaceholders.java
index 5a7926c..7481fec 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/adventure/AdventurePlaceholders.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/adventure/AdventurePlaceholders.java
@@ -1,6 +1,5 @@
package com.github.imdmk.playtime.platform.adventure;
-import com.github.imdmk.playtime.shared.validate.Validator;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
@@ -10,13 +9,6 @@
import java.util.LinkedHashMap;
import java.util.Map;
-/**
- * Immutable container mapping literal placeholder keys to Adventure {@link Component} values.
- *
- * Instances are created via the {@link Builder}. Once built, the mapping is read-only.
- *
- * Thread-safety: Fully immutable and safe for concurrent use.
- */
public final class AdventurePlaceholders {
private static final AdventurePlaceholders EMPTY = new AdventurePlaceholders(Map.of());
@@ -24,130 +16,59 @@ public final class AdventurePlaceholders {
private final Map map;
private AdventurePlaceholders(@NotNull Map map) {
- Validator.notNull(map, "map");
this.map = Collections.unmodifiableMap(map);
}
- /**
- * Returns an unmodifiable view of all placeholder mappings.
- *
- * @return unmodifiable placeholder map
- */
@Unmodifiable
- @NotNull
public Map asMap() {
return map;
}
- /**
- * Returns the number of registered placeholders.
- *
- * @return placeholder count
- */
public int size() {
return map.size();
}
- /**
- * Checks if the placeholder map is empty.
- *
- * @return {@code true} if no placeholders are defined
- */
public boolean isEmpty() {
return map.isEmpty();
}
- /**
- * Returns a shared immutable empty instance.
- *
- * @return empty placeholder container
- */
- public static @NotNull AdventurePlaceholders empty() {
+ public static AdventurePlaceholders empty() {
return EMPTY;
}
- /**
- * Creates a new builder for {@link AdventurePlaceholders}.
- *
- * @return new builder instance
- */
- public static @NotNull Builder builder() {
+ public static Builder builder() {
return new Builder();
}
- /**
- * Fluent builder for {@link AdventurePlaceholders}.
- */
public static final class Builder {
private final Map entries = new LinkedHashMap<>();
- /**
- * Adds a literal → component mapping.
- *
- * @param key literal placeholder key
- * @param value replacement component
- * @return this builder for chaining
- */
@Contract("_,_ -> this")
- public @NotNull Builder with(@NotNull String key, @NotNull Component value) {
- Validator.notNull(key, "key");
- Validator.notNull(value, "value");
+ public Builder with(@NotNull String key, @NotNull Component value) {
this.entries.put(key, value);
return this;
}
- /**
- * Adds a literal → plain text mapping (converted to {@link Component#text(String)}).
- *
- * @param key literal placeholder key
- * @param value replacement text
- * @return this builder for chaining
- */
@Contract("_,_ -> this")
- public @NotNull Builder with(@NotNull String key, @NotNull String value) {
- Validator.notNull(key, "key cannot be null");
- Validator.notNull(value, "value cannot be null");
+ public Builder with(@NotNull String key, @NotNull String value) {
this.entries.put(key, Component.text(value));
return this;
}
- /**
- * Adds all entries from another {@link AdventurePlaceholders}.
- *
- * @param other another placeholder container
- * @return this builder for chaining
- */
@Contract("_ -> this")
- public @NotNull Builder with(@NotNull AdventurePlaceholders other) {
- Validator.notNull(other, "other cannot be null");
+ public Builder with(@NotNull AdventurePlaceholders other) {
this.entries.putAll(other.asMap());
return this;
}
- /**
- * Adds a placeholder using any object value.
- * The value is converted to plain text via {@link String#valueOf(Object)}.
- *
- * @param key placeholder key
- * @param value object to convert and insert
- * @return this builder for chaining
- * @throws NullPointerException if key or value is null
- */
@Contract("_,_ -> this")
- public @NotNull Builder with(@NotNull String key, @NotNull Object value) {
- Validator.notNull(key, "key cannot be null");
- Validator.notNull(value, "value cannot be null");
+ public Builder with(@NotNull String key, @NotNull Object value) {
this.entries.put(key, Component.text(String.valueOf(value)));
return this;
}
- /**
- * Builds an immutable {@link AdventurePlaceholders} instance.
- *
- * @return immutable placeholder container
- */
- public @NotNull AdventurePlaceholders build() {
+ public AdventurePlaceholders build() {
if (this.entries.isEmpty()) {
return EMPTY;
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/event/BukkitEventCaller.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/event/BukkitEventCaller.java
new file mode 100644
index 0000000..775e007
--- /dev/null
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/event/BukkitEventCaller.java
@@ -0,0 +1,34 @@
+package com.github.imdmk.playtime.platform.event;
+
+import com.github.imdmk.playtime.injector.ComponentPriority;
+import com.github.imdmk.playtime.injector.annotations.Service;
+import com.github.imdmk.playtime.platform.scheduler.TaskScheduler;
+import org.bukkit.Server;
+import org.bukkit.event.Event;
+import org.jetbrains.annotations.NotNull;
+import org.panda_lang.utilities.inject.annotations.Inject;
+
+@Service(priority = ComponentPriority.LOW)
+public final class BukkitEventCaller implements EventCaller {
+
+ private final Server server;
+ private final TaskScheduler scheduler;
+
+ @Inject
+ public BukkitEventCaller(@NotNull Server server, @NotNull TaskScheduler scheduler) {
+ this.server = server;
+ this.scheduler = scheduler;
+ }
+
+ @Override
+ public E callEvent(@NotNull E event) {
+ if (event.isAsynchronous() || server.isPrimaryThread()) {
+ server.getPluginManager().callEvent(event);
+ return event;
+ }
+
+ scheduler.runSync(() -> server.getPluginManager().callEvent(event));
+ return event;
+ }
+
+}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/event/EventCaller.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/event/EventCaller.java
new file mode 100644
index 0000000..4de83c9
--- /dev/null
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/event/EventCaller.java
@@ -0,0 +1,10 @@
+package com.github.imdmk.playtime.platform.event;
+
+import org.bukkit.event.Event;
+import org.jetbrains.annotations.NotNull;
+
+public interface EventCaller {
+
+ E callEvent(@NotNull E event);
+
+}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/events/BukkitEventCaller.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/events/BukkitEventCaller.java
deleted file mode 100644
index 5a7a3a5..0000000
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/events/BukkitEventCaller.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.github.imdmk.playtime.platform.events;
-
-import com.github.imdmk.playtime.platform.scheduler.TaskScheduler;
-import com.github.imdmk.playtime.shared.validate.Validator;
-import org.bukkit.Server;
-import org.bukkit.event.Event;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Utility wrapper for safely firing Bukkit {@link Event}s.
- * Ensures that synchronous events are always fired on the primary server thread.
- */
-public final class BukkitEventCaller {
-
- private final Server server;
- private final TaskScheduler scheduler;
-
- public BukkitEventCaller(@NotNull Server server, @NotNull TaskScheduler scheduler) {
- this.server = Validator.notNull(server, "server cannot be null");
- this.scheduler = Validator.notNull(scheduler, "scheduler cannot be null");
- }
-
- /**
- * Calls the specified Bukkit event ensuring correct thread usage:
- *
- * - Asynchronous events are fired on the current thread;
- * - Synchronous events are fired on the primary server thread.
- *
- */
- public T callEvent(@NotNull T event) {
- Validator.notNull(event, "event cannot be null");
-
- if (event.isAsynchronous()) {
- server.getPluginManager().callEvent(event);
- return event;
- }
-
- if (server.isPrimaryThread()) {
- server.getPluginManager().callEvent(event);
- } else {
- scheduler.runSync(() -> server.getPluginManager().callEvent(event));
- }
-
- return event;
- }
-}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/events/BukkitListenerRegistrar.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/events/BukkitListenerRegistrar.java
deleted file mode 100644
index 10f1f0b..0000000
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/events/BukkitListenerRegistrar.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.github.imdmk.playtime.platform.events;
-
-import com.github.imdmk.playtime.shared.validate.Validator;
-import org.bukkit.event.Listener;
-import org.bukkit.plugin.Plugin;
-import org.jetbrains.annotations.NotNull;
-import org.panda_lang.utilities.inject.Injector;
-
-/**
- * Utility component responsible for registering Bukkit {@link Listener}s.
- *
- * This registrar provides two registration modes:
- *
- * - Direct registration of pre-instantiated listener objects.
- * - Automatic instantiation and field injection through {@link Injector}.
- *
- *
- * All listeners are registered using the plugin's {@link org.bukkit.plugin.PluginManager}.
- */
-public final class BukkitListenerRegistrar {
-
- private final Plugin plugin;
-
- /**
- * Creates a new registrar for the given Bukkit plugin.
- *
- * @param plugin the plugin instance used for listener registration
- * @throws NullPointerException if the plugin is null
- */
- public BukkitListenerRegistrar(@NotNull Plugin plugin) {
- this.plugin = Validator.notNull(plugin, "plugin cannot be null");
- }
-
- /**
- * Registers the provided listener instances with the Bukkit {@link org.bukkit.plugin.PluginManager}.
- *
- * @param listeners the listener instances to register
- * @throws NullPointerException if the listeners array or any listener is null
- */
- public void register(@NotNull Listener... listeners) {
- Validator.notNull(listeners, "listeners cannot be null");
- for (final Listener listener : listeners) {
- plugin.getServer().getPluginManager().registerEvents(listener, plugin);
- }
- }
-
- /**
- * Creates and registers listeners using the provided {@link Injector}.
- *
- * Each listener class is instantiated and its dependencies are injected automatically.
- *
- * @param injector the dependency injector to use for listener instantiation
- * @param listeners the listener classes to create and register
- * @throws NullPointerException if the injector, the listener array, or any class is null
- */
- @SafeVarargs
- public final void register(@NotNull Injector injector, @NotNull Class extends Listener>... listeners) {
- Validator.notNull(injector, "injector cannot be null");
- Validator.notNull(listeners, "listeners cannot be null");
-
- for (final Class extends Listener> listenerClass : listeners) {
- register(injector.newInstance(listenerClass));
- }
- }
-}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/GuiModule.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/GuiModule.java
deleted file mode 100644
index c2ebe85..0000000
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/GuiModule.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.github.imdmk.playtime.platform.gui;
-
-import com.github.imdmk.playtime.infrastructure.module.Module;
-import com.github.imdmk.playtime.platform.gui.render.GuiRenderer;
-import com.github.imdmk.playtime.platform.gui.render.TriumphGuiRenderer;
-import com.github.imdmk.playtime.platform.gui.view.GuiOpener;
-import org.jetbrains.annotations.NotNull;
-import org.panda_lang.utilities.inject.Injector;
-import org.panda_lang.utilities.inject.Resources;
-
-public final class GuiModule implements Module {
-
- private GuiOpener guiOpener;
- private GuiRenderer guiRenderer;
-
- @Override
- public void bind(@NotNull Resources resources) {
- resources.on(GuiOpener.class).assignInstance(() -> this.guiOpener);
- resources.on(GuiRenderer.class).assignInstance(() -> this.guiRenderer);
- }
-
- @Override
- public void init(@NotNull Injector injector) {
- this.guiOpener = injector.newInstance(GuiOpener.class);
- this.guiRenderer = injector.newInstance(TriumphGuiRenderer.class);
- }
-
- @Override
- public int order() {
- return 10;
- }
-}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/GuiRegistry.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/GuiRegistry.java
index c996139..2772c24 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/GuiRegistry.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/GuiRegistry.java
@@ -1,6 +1,7 @@
package com.github.imdmk.playtime.platform.gui;
-import com.github.imdmk.playtime.shared.validate.Validator;
+import com.github.imdmk.playtime.injector.ComponentPriority;
+import com.github.imdmk.playtime.injector.annotations.Service;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
@@ -10,26 +11,14 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-/**
- * Thread-safe registry of {@link IdentifiableGui}, keyed by normalized id.
- * Invariant: at most one GUI per concrete class (maintained class index).
- */
+@Service(priority = ComponentPriority.LOW)
public final class GuiRegistry {
private final Map byId = new ConcurrentHashMap<>();
private final Map, IdentifiableGui> byClass = new ConcurrentHashMap<>();
- /**
- * Registers (or replaces) GUI by its normalized identifier.
- * Also updates class index (one instance per class).
- *
- * @return previously registered GUI under the same id, or {@code null}.
- */
- @Nullable
- public IdentifiableGui register(@NotNull IdentifiableGui gui) {
- Validator.notNull(gui, "gui cannot be null");
- final String id = normalize(Validator.notNull(gui.getId(), "gui identifier cannot be null"));
-
+ public void register(@NotNull IdentifiableGui gui) {
+ final String id = normalize(gui.getId());
final IdentifiableGui previous = byId.put(id, gui);
// maintain class index (assume single instance per class)
@@ -40,18 +29,10 @@ public IdentifiableGui register(@NotNull IdentifiableGui gui) {
if (previous != null && previous.getClass() != type) {
byClass.compute(previous.getClass(), (k, current) -> current == previous ? null : current);
}
- return previous;
}
- /**
- * Registers GUI only if absent under the same id.
- *
- * @return {@code true} if registered, {@code false} if id existed.
- */
public boolean registerIfAbsent(@NotNull IdentifiableGui gui) {
- Validator.notNull(gui, "gui cannot be null");
- final String id = normalize(Validator.notNull(gui.getId(), "gui identifier cannot be null"));
-
+ final String id = normalize(gui.getId());
final IdentifiableGui existing = byId.putIfAbsent(id, gui);
if (existing == null) {
// we won the race; update class index
@@ -61,12 +42,9 @@ public boolean registerIfAbsent(@NotNull IdentifiableGui gui) {
return false;
}
- /**
- * Unregisters GUI by id. Updates class index if pointing to same instance.
- */
@Nullable
public IdentifiableGui unregister(@NotNull String id) {
- final String key = normalize(Validator.notNull(id, "id cannot be null"));
+ final String key = normalize(id);
final IdentifiableGui removed = byId.remove(key);
if (removed != null) {
byClass.compute(removed.getClass(), (k, current) -> current == removed ? null : current);
@@ -74,40 +52,28 @@ public IdentifiableGui unregister(@NotNull String id) {
return removed;
}
- /**
- * Case-insensitive lookup by id (whitespace-insensitive).
- */
@Nullable
public IdentifiableGui getById(@NotNull String id) {
- final String key = normalize(Validator.notNull(id, "id cannot be null"));
- return byId.get(key);
+ return byId.get(normalize(id));
}
- /**
- * O(1) exact type lookup. Assumes at most one instance per class.
- */
@Nullable
+ @SuppressWarnings("unchecked")
public T getByClass(@NotNull Class type) {
- Validator.notNull(type, "type cannot be null");
final IdentifiableGui gui = byClass.get(type);
- @SuppressWarnings("unchecked")
- final T cast = (T) gui;
- return cast;
+ return (T) gui;
}
public boolean isRegistered(@NotNull String id) {
- final String key = normalize(Validator.notNull(id, "id cannot be null"));
- return byId.containsKey(key);
+ return byId.containsKey(normalize(id));
}
- /** Immutable snapshot of normalized ids. */
@Unmodifiable
public Set ids() {
return Set.copyOf(byId.keySet());
}
- /** Current strategy: trim + lowercased (Locale.ROOT). */
- private static String normalize(@NotNull String id) {
+ private static String normalize(String id) {
final String trimmed = id.trim();
return trimmed.toLowerCase(Locale.ROOT);
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/GuiType.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/GuiType.java
index a17c8e5..1dd71ac 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/GuiType.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/GuiType.java
@@ -1,33 +1,8 @@
package com.github.imdmk.playtime.platform.gui;
-/**
- * Defines the supported GUI layout types within the plugin.
- *
- * Each type represents a different interaction model for displaying items.
- */
public enum GuiType {
-
- /**
- * A fixed-size GUI without pagination or scrolling.
- * Suitable for simple static interfaces.
- */
STANDARD,
-
- /**
- * A multipage GUI used for displaying large sets of items.
- * Provides navigation between pages.
- */
PAGINATED,
-
- /**
- * A GUI that supports vertical scrolling.
- * Ideal for lists of items exceeding the visible height.
- */
SCROLLING_VERTICAL,
-
- /**
- * A GUI that supports horizontal scrolling.
- * Useful for side-by-side item navigation.
- */
SCROLLING_HORIZONTAL
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/IdentifiableGui.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/IdentifiableGui.java
index f9f0a9d..cacc917 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/IdentifiableGui.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/IdentifiableGui.java
@@ -1,18 +1,9 @@
package com.github.imdmk.playtime.platform.gui;
import org.jetbrains.annotations.NotNull;
-/**
- * Represents a GUI component that can be uniquely identified by a string identifier.
- *
- * Useful for registering and retrieving GUI instances by their identifier.
- */
@FunctionalInterface
public interface IdentifiableGui {
- /**
- * Returns the unique identifier for this GUI.
- *
- * @return the non-null unique identifier string
- */
@NotNull String getId();
+
}
\ No newline at end of file
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/config/ConfigurableGui.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/config/ConfigurableGui.java
index a15678f..44a0e4e 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/config/ConfigurableGui.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/config/ConfigurableGui.java
@@ -2,27 +2,13 @@
import com.github.imdmk.playtime.platform.gui.GuiType;
import net.kyori.adventure.text.Component;
-import org.jetbrains.annotations.NotNull;
-/**
- * Represents a configurable GUI loaded from configuration.
- * Implementations should provide all basic GUI metadata and content definitions.
- */
public interface ConfigurableGui {
- /**
- * @return GUI title as Adventure {@link Component}
- */
- @NotNull Component title();
+ Component title();
- /**
- * @return GUI type (e.g. {@link GuiType#STANDARD}, {@link GuiType#PAGINATED})
- */
- @NotNull GuiType type();
+ GuiType type();
- /**
- * @return GUI rows
- */
int rows();
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/config/GuiConfig.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/config/GuiConfig.java
index 4b08026..fec1fbe 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/config/GuiConfig.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/config/GuiConfig.java
@@ -2,7 +2,8 @@
import com.github.imdmk.playtime.config.ConfigSection;
import com.github.imdmk.playtime.feature.playtime.gui.PlayTimeTopGuiConfig;
-import com.github.imdmk.playtime.platform.adventure.ComponentSerializer;
+import com.github.imdmk.playtime.injector.annotations.ConfigFile;
+import com.github.imdmk.playtime.platform.adventure.AdventureComponentSerializer;
import com.github.imdmk.playtime.platform.gui.item.ItemGuiSerializer;
import com.github.imdmk.playtime.platform.serdes.EnchantmentSerializer;
import com.github.imdmk.playtime.platform.serdes.SoundSerializer;
@@ -10,18 +11,19 @@
import eu.okaeri.configs.serdes.OkaeriSerdesPack;
import org.jetbrains.annotations.NotNull;
+@ConfigFile
public final class GuiConfig extends ConfigSection {
@Comment({"#", "# Playtime top GUI", "#"})
- public PlayTimeTopGuiConfig playtimeTopGui = new PlayTimeTopGuiConfig();
+ public PlayTimeTopGuiConfig playTimeTopGui = new PlayTimeTopGuiConfig();
@Comment({"#", "# Navigation Bar", "#"})
public NavigationBarConfig navigationBar = new NavigationBarConfig();
@Override
- public @NotNull OkaeriSerdesPack getSerdesPack() {
+ public @NotNull OkaeriSerdesPack serdesPack() {
return registry -> {
- registry.register(new ComponentSerializer());
+ registry.register(new AdventureComponentSerializer());
registry.register(new ItemGuiSerializer());
registry.register(new EnchantmentSerializer());
registry.register(new SoundSerializer());
@@ -29,7 +31,7 @@ public final class GuiConfig extends ConfigSection {
}
@Override
- public @NotNull String getFileName() {
+ public @NotNull String fileName() {
return "guiConfig.yml";
}
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/config/NavigationBarConfig.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/config/NavigationBarConfig.java
index 8e828c1..c3755a5 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/config/NavigationBarConfig.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/config/NavigationBarConfig.java
@@ -6,12 +6,6 @@
import eu.okaeri.configs.annotation.Comment;
import org.bukkit.Material;
-/**
- * Configuration for navigation items used in paginated GUIs.
- *
- * Defines visual representation and behavior for navigation controls:
- * next, previous, and exit buttons displayed in inventory-based interfaces.
- */
public final class NavigationBarConfig extends OkaeriConfig {
@Comment({
@@ -100,4 +94,5 @@ public final class NavigationBarConfig extends OkaeriConfig {
" "
))
.build();
+
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/factory/GuiBuilderFactory.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/factory/GuiBuilderFactory.java
index e5cfff8..d901870 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/factory/GuiBuilderFactory.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/factory/GuiBuilderFactory.java
@@ -1,39 +1,20 @@
package com.github.imdmk.playtime.platform.gui.factory;
import com.github.imdmk.playtime.platform.gui.GuiType;
-import com.github.imdmk.playtime.shared.validate.Validator;
import dev.triumphteam.gui.builder.gui.BaseGuiBuilder;
import dev.triumphteam.gui.components.ScrollType;
import dev.triumphteam.gui.guis.Gui;
-import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
-/**
- * Factory for creating TriumphGUI {@link BaseGuiBuilder} instances
- * based on a provided {@link GuiType}.
- *
- * Supports standard, paginated, and scrolling (vertical/horizontal) GUIs.
- */
public final class GuiBuilderFactory {
private GuiBuilderFactory() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated.");
}
- /**
- * Returns a TriumphGUI builder matching the given {@link GuiType}.
- *
- * @param type the GUI type
- * @param rows the GUI rows
- * @return a new {@link BaseGuiBuilder} instance for the given type
- * @throws IllegalArgumentException if {@code type} is {@code null}
- */
- @Contract(pure = true)
- public static @NotNull BaseGuiBuilder, ?> forType(@NotNull GuiType type, int rows) {
- Validator.notNull(type, "type cannot be null");
-
+ public static BaseGuiBuilder, ?> forType(@NotNull GuiType type, int rows) {
return switch (type) {
case STANDARD -> Gui.gui().rows(rows);
case PAGINATED -> Gui.paginated().rows(rows);
@@ -42,20 +23,8 @@ private GuiBuilderFactory() {
};
}
- /**
- * Creates and immediately customizes a TriumphGUI builder.
- *
- * @param type the GUI type
- * @param rows the GUI rows
- * @param editConsumer consumer for post-creation customization (e.g., size, disableAllInteractions)
- * @return a modified {@link BaseGuiBuilder} instance
- * @throws IllegalArgumentException if {@code type} or {@code editConsumer} is {@code null}
- */
- public static @NotNull BaseGuiBuilder, ?> forType(@NotNull GuiType type, int rows, @NotNull Consumer> editConsumer) {
- Validator.notNull(type, "type cannot be null");
- Validator.notNull(editConsumer, "editConsumer cannot be null");
-
- BaseGuiBuilder, ?> builder = forType(type, rows);
+ public static BaseGuiBuilder, ?> forType(@NotNull GuiType type, int rows, @NotNull Consumer> editConsumer) {
+ final BaseGuiBuilder, ?> builder = forType(type, rows);
editConsumer.accept(builder);
return builder;
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/factory/GuiFactory.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/factory/GuiFactory.java
index cee734d..190904a 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/factory/GuiFactory.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/factory/GuiFactory.java
@@ -1,54 +1,25 @@
package com.github.imdmk.playtime.platform.gui.factory;
import com.github.imdmk.playtime.platform.gui.config.ConfigurableGui;
-import com.github.imdmk.playtime.shared.validate.Validator;
import dev.triumphteam.gui.guis.BaseGui;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
-/**
- * Factory for creating {@link BaseGui} instances from {@link ConfigurableGui}.
- *
- * Responsibilities:
- *
- * - Delegate to {@link GuiBuilderFactory} based on configured type,
- * - Apply base attributes (e.g. title),
- * - Optionally allow post-creation customization via a {@link Consumer}.
- *
- */
public final class GuiFactory {
private GuiFactory() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated.");
}
- /**
- * Builds a GUI instance from the provided configuration.
- *
- * @param config the GUI configuration
- * @return a new {@link BaseGui} instance
- * @throws IllegalArgumentException if the GUI type is unsupported
- */
- public static @NotNull BaseGui build(@NotNull ConfigurableGui config) {
- Validator.notNull(config, "config cannot be null");
+ public static BaseGui build(@NotNull ConfigurableGui config) {
return GuiBuilderFactory.forType(config.type(), config.rows())
.title(config.title())
.create();
}
- /**
- * Builds and immediately customizes a GUI using the provided consumer.
- *
- * @param config the GUI configuration
- * @param editConsumer consumer to modify the GUI instance before returning
- * @return the configured {@link BaseGui}
- */
- public static @NotNull BaseGui build(@NotNull ConfigurableGui config, @NotNull Consumer editConsumer) {
- Validator.notNull(config, "config cannot be null");
- Validator.notNull(editConsumer, "editConsumer cannot be null");
-
- BaseGui gui = build(config);
+ public static BaseGui build(@NotNull ConfigurableGui config, @NotNull Consumer editConsumer) {
+ final BaseGui gui = build(config);
editConsumer.accept(gui);
return gui;
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemGui.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemGui.java
index f9f967b..c0db2da 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemGui.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemGui.java
@@ -1,6 +1,5 @@
package com.github.imdmk.playtime.platform.gui.item;
-import com.github.imdmk.playtime.shared.validate.Validator;
import net.kyori.adventure.text.Component;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
@@ -16,12 +15,6 @@
import java.util.List;
import java.util.Map;
-/**
- * Immutable data model representing a GUI item definition.
- *
- * Pure data – no logic, no rendering.
- * Used to describe items in configuration and GUI assembly layers.
- */
public record ItemGui(
@NotNull Material material,
@NotNull Component name,
@@ -34,10 +27,6 @@ public record ItemGui(
) {
public ItemGui {
- Validator.notNull(material, "material cannot be null");
- Validator.notNull(name, "name cannot be null");
- Validator.notNull(lore, "lore cannot be null");
-
lore = List.copyOf(lore);
if (enchantments != null) {
@@ -67,21 +56,20 @@ public static final class Builder {
@CheckReturnValue
@Contract(value = "_ -> this", mutates = "this")
public Builder material(@NotNull Material material) {
- this.material = Validator.notNull(material, "material cannot be null");
+ this.material = material;
return this;
}
@CheckReturnValue
@Contract(value = "_ -> this", mutates = "this")
public Builder name(@NotNull Component name) {
- this.name = Validator.notNull(name, "name cannot be null");
+ this.name = name;
return this;
}
@CheckReturnValue
@Contract(value = "_ -> this", mutates = "this")
public Builder lore(@NotNull List lore) {
- Validator.notNull(lore, "lore cannot be null");
this.lore = List.copyOf(lore);
return this;
}
@@ -117,9 +105,6 @@ public Builder requiredPermission(@Nullable String permission) {
@CheckReturnValue
@Contract(value = "_, _ -> this", mutates = "this")
public Builder addEnchantment(@NotNull Enchantment enchantment, @NotNull Integer level) {
- Validator.notNull(enchantment, "enchantment cannot be null");
- Validator.notNull(level, "level cannot be null");
-
Map newEnchantments = new HashMap<>(this.enchantments);
newEnchantments.put(enchantment, level);
this.enchantments = Map.copyOf(newEnchantments);
@@ -129,8 +114,6 @@ public Builder addEnchantment(@NotNull Enchantment enchantment, @NotNull Integer
@CheckReturnValue
@Contract(value = "_ -> this", mutates = "this")
public Builder addFlags(@NotNull ItemFlag... toAdd) {
- Validator.notNull(toAdd, "flags cannot be null");
-
List newFlags = new ArrayList<>(this.flags);
Collections.addAll(newFlags, toAdd);
this.flags = List.copyOf(newFlags);
@@ -140,15 +123,12 @@ public Builder addFlags(@NotNull ItemFlag... toAdd) {
@CheckReturnValue
@Contract(value = "_ -> this", mutates = "this")
public Builder appendLore(@NotNull Component... lines) {
- Validator.notNull(lines, "lines cannot be null");
-
List newLore = new ArrayList<>(this.lore);
Collections.addAll(newLore, lines);
this.lore = List.copyOf(newLore);
return this;
}
- @NotNull
public ItemGui build() {
return new ItemGui(
this.material,
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemGuiSerializer.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemGuiSerializer.java
index 5eacf92..d48aac2 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemGuiSerializer.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemGuiSerializer.java
@@ -24,22 +24,22 @@ public void serialize(@NotNull ItemGui item, @NotNull SerializationData data, @N
data.add("name", item.name(), Component.class);
data.addCollection("lore", item.lore(), Component.class);
- var slot = item.slot();
+ final var slot = item.slot();
if (slot != null) {
data.add("slot", slot, Integer.class);
}
- var enchantments = item.enchantments();
+ final var enchantments = item.enchantments();
if (enchantments != null && !enchantments.isEmpty()) {
data.addAsMap("enchantments", item.enchantments(), Enchantment.class, Integer.class);
}
- var flags = item.flags();
+ final var flags = item.flags();
if (flags != null && !flags.isEmpty()) {
data.addCollection("flags", flags, ItemFlag.class);
}
- var permission = item.requiredPermission();
+ final var permission = item.requiredPermission();
if (permission != null && !permission.isBlank()) {
data.add("permission", permission, String.class);
}
@@ -47,14 +47,14 @@ public void serialize(@NotNull ItemGui item, @NotNull SerializationData data, @N
@Override
public ItemGui deserialize(@NotNull DeserializationData data, @NotNull GenericsDeclaration generics) {
- var material = data.get("material", Material.class);
- var name = data.get("name", Component.class);
- var lore = data.getAsList("lore", Component.class);
+ final var material = data.get("material", Material.class);
+ final var name = data.get("name", Component.class);
+ final var lore = data.getAsList("lore", Component.class);
- var slot = data.get("slot", Integer.class);
- var enchantments = data.getAsMap("enchantments", Enchantment.class, Integer.class);
- var flags = data.getAsList("flags", ItemFlag.class);
- var permission = data.get("permission", String.class);
+ final var slot = data.get("slot", Integer.class);
+ final var enchantments = data.getAsMap("enchantments", Enchantment.class, Integer.class);
+ final var flags = data.getAsList("flags", ItemFlag.class);
+ final var permission = data.get("permission", String.class);
return new ItemGui(
material,
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemGuiTransformer.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemGuiTransformer.java
index 50b9954..35b309d 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemGuiTransformer.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemGuiTransformer.java
@@ -1,6 +1,5 @@
package com.github.imdmk.playtime.platform.gui.item;
-import com.github.imdmk.playtime.shared.validate.Validator;
import dev.triumphteam.gui.builder.item.BaseItemBuilder;
import dev.triumphteam.gui.builder.item.ItemBuilder;
import dev.triumphteam.gui.components.GuiAction;
@@ -12,74 +11,31 @@
import java.util.function.Consumer;
-/**
- * Stateless utility that converts {@link ItemGui} definitions into Triumph {@link GuiItem}s.
- *
- * Thread-safety: Pure transformation; prefer main thread for Bukkit objects.
- */
public final class ItemGuiTransformer {
private ItemGuiTransformer() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
- /**
- * Creates a {@link GuiItem} with a no-op click handler.
- *
- * @param item item definition (non-null)
- * @return a new {@link GuiItem} instance
- * @throws IllegalArgumentException if {@code item} is {@code null}
- */
- public static @NotNull GuiItem toGuiItem(@NotNull ItemGui item) {
+ public static GuiItem toGuiItem(@NotNull ItemGui item) {
return toGuiItem(item, (e) -> {}, (b) -> {});
}
- /**
- * Creates a {@link GuiItem} wiring a {@link GuiAction} click handler.
- *
- * @param item item (non-null)
- * @param onClick click handler (non-null)
- * @return a new {@link GuiItem} instance
- * @throws IllegalArgumentException if any argument is {@code null}
- */
- public static @NotNull GuiItem toGuiItem(@NotNull ItemGui item, @NotNull GuiAction onClick) {
+ public static GuiItem toGuiItem(@NotNull ItemGui item, @NotNull GuiAction onClick) {
return toGuiItem(item, onClick, (b) -> {});
}
- /**
- * Creates a {@link GuiItem} wiring a standard {@link Consumer} click handler.
- * Convenience overload that adapts to Triumph's {@link GuiAction}.
- *
- * @param item item (non-null)
- * @param onClick click handler (non-null)
- * @return a new {@link GuiItem} instance
- * @throws IllegalArgumentException if any argument is {@code null}
- */
- public static @NotNull GuiItem toGuiItem(@NotNull ItemGui item, @NotNull Consumer onClick) {
+ public static GuiItem toGuiItem(@NotNull ItemGui item, @NotNull Consumer onClick) {
return toGuiItem(item, onClick::accept, (b) -> {});
}
- /**
- * Creates a {@link GuiItem} with handler and optional builder editor.
- *
- * @param item item (non-null)
- * @param onClick click handler (non-null)
- * @param builderEditor item builder editor (non-null)
- * @return a new {@link GuiItem} instance
- * @throws IllegalArgumentException if any argument is {@code null}
- */
- public static @NotNull GuiItem toGuiItem(
+ public static GuiItem toGuiItem(
@NotNull ItemGui item,
@NotNull GuiAction onClick,
@NotNull Consumer> builderEditor
) {
- Validator.notNull(item, "item cannot be null");
- Validator.notNull(onClick, "onClick cannot be null");
- Validator.notNull(builderEditor, "builderEditor cannot be null");
-
- final Material material = item.material();
- final BaseItemBuilder> builder =
- material == Material.PLAYER_HEAD ? ItemBuilder.skull() : ItemBuilder.from(material);
+ final var material = item.material();
+ final var builder = material == Material.PLAYER_HEAD ? ItemBuilder.skull() : ItemBuilder.from(material);
builder.name(item.name());
builder.lore(item.lore());
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemVariantPermissionResolver.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemVariantPermissionResolver.java
index ce50b59..a6c8051 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemVariantPermissionResolver.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemVariantPermissionResolver.java
@@ -1,44 +1,11 @@
package com.github.imdmk.playtime.platform.gui.item;
import com.github.imdmk.playtime.platform.gui.render.RenderContext;
-import com.github.imdmk.playtime.shared.validate.Validator;
import org.bukkit.entity.HumanEntity;
import org.jetbrains.annotations.NotNull;
-/**
- * Resolves which {@link ItemGui} variant should be displayed to a viewer
- * based on their permission state.
- *
- * This implementation iterates through candidate items in order and returns
- * the first one that either:
- *
- * - Has no required permission ({@code requiredPermission() == null}), or
- * - Has a permission that the viewer possesses, as determined by
- * {@link RenderContext#permissionEvaluator()}.
- *
- * If no candidate matches, a predefined fallback item is returned.
- *
- * Usage: Typically used by GUI renderers to determine which
- * item variant to display for users with different roles or permission levels.
- *
- * Thread-safety: This resolver is stateless and thread-safe.
- *
- * @see ItemGui
- * @see ItemVariantResolver
- * @see RenderContext
- */
public final class ItemVariantPermissionResolver implements ItemVariantResolver {
- /**
- * Resolves the first matching {@link ItemGui} variant visible to the given viewer.
- *
- * @param viewer the player or entity viewing the GUI (non-null)
- * @param context current rendering context, providing permission evaluation (non-null)
- * @param candidates ordered list of possible item variants (non-null)
- * @param fallback default item to return if no candidate matches (non-null)
- * @return the first permitted item variant, or {@code fallback} if none are allowed
- * @throws NullPointerException if any argument is null
- */
@Override
public ItemGui resolve(
@NotNull HumanEntity viewer,
@@ -46,11 +13,6 @@ public ItemGui resolve(
@NotNull Iterable extends ItemGui> candidates,
@NotNull ItemGui fallback
) {
- Validator.notNull(viewer, "viewer cannot be null");
- Validator.notNull(context, "context cannot be null");
- Validator.notNull(candidates, "candidates cannot be null");
- Validator.notNull(fallback, "fallback cannot be null");
-
for (final ItemGui item : candidates) {
if (item == null) {
continue;
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemVariantResolver.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemVariantResolver.java
index 163011d..328a13c 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemVariantResolver.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/item/ItemVariantResolver.java
@@ -4,35 +4,8 @@
import org.bukkit.entity.HumanEntity;
import org.jetbrains.annotations.NotNull;
-/**
- * Defines a strategy for selecting which {@link ItemGui} variant
- * should be displayed to a specific viewer during GUI rendering.
- *
- * Implementations of this interface encapsulate different
- * resolution logics — e.g., by permission, by user state,
- * by contextual conditions, or by custom business rules.
- *
- * The resolver is typically used within GUI frameworks to decide
- * which visual representation of an item (variant) to render for a given player.
- *
- * Thread-safety: Implementations should be stateless and thread-safe.
- *
- * @see ItemGui
- * @see RenderContext
- * @see ItemVariantPermissionResolver
- */
public interface ItemVariantResolver {
- /**
- * Resolves the most appropriate {@link ItemGui} variant to display.
- *
- * @param viewer the player or entity viewing the GUI (non-null)
- * @param context the current rendering context providing permission checks, locale, etc. (non-null)
- * @param candidates iterable collection of possible item variants, evaluated in order (non-null)
- * @param fallback default item variant to use if none match (non-null)
- * @return the resolved item variant, never {@code null} (at least {@code fallback})
- * @throws NullPointerException if any parameter is null
- */
ItemGui resolve(@NotNull HumanEntity viewer,
@NotNull RenderContext context,
@NotNull Iterable extends ItemGui> candidates,
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/GuiRenderer.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/GuiRenderer.java
index 2f6fcb8..6015bfa 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/GuiRenderer.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/GuiRenderer.java
@@ -9,10 +9,6 @@
import java.util.function.Consumer;
-/**
- * Renders and places {@link ItemGui} into {@link BaseGui} instances.
- * Invoke only on the Bukkit main thread.
- */
public interface GuiRenderer {
@Contract(mutates = "param1")
@@ -26,10 +22,6 @@ default void setItem(@NotNull BaseGui gui,
setItem(gui, slot, item, context, options, onClick, b -> {});
}
- /**
- * Sets the item in a specific slot (overwrites existing content).
- * Supports per-slot customization via {@code builderEditor}.
- */
@Contract(mutates = "param1")
void setItem(@NotNull BaseGui gui,
int slot,
@@ -81,10 +73,6 @@ default void addItem(@NotNull BaseGui gui,
addItem(gui, item, context, options, onClick, b -> {});
}
- /**
- * Adds the item to the next free slot.
- * Supports per-slot customization via {@code builderEditor}.
- */
@Contract(mutates = "param1")
void addItem(@NotNull BaseGui gui,
@NotNull ItemGui item,
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/NoPermissionPolicy.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/NoPermissionPolicy.java
index ee7cb96..4ce4519 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/NoPermissionPolicy.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/NoPermissionPolicy.java
@@ -1,19 +1,6 @@
package com.github.imdmk.playtime.platform.gui.render;
-/**
- * Defines how a GUI element should behave when the viewer lacks
- * the required permission to interact with or view the item.
- */
public enum NoPermissionPolicy {
-
- /**
- * The item is completely hidden and not placed in the GUI.
- */
HIDE,
-
- /**
- * The item is still visible but interaction is disabled.
- * Clicking it will trigger the "onDenied" consumer if provided.
- */
DISABLE
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/PermissionEvaluator.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/PermissionEvaluator.java
index 2c27ab3..f7e5a3c 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/PermissionEvaluator.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/PermissionEvaluator.java
@@ -3,23 +3,8 @@
import org.bukkit.entity.HumanEntity;
import org.jetbrains.annotations.NotNull;
-/**
- * Strategy interface for checking player permissions.
- *
- * This abstraction allows GUIs and renderers to remain independent
- * from the underlying permission system (e.g. Bukkit, Vault, LuckPerms).
- *
- * Implementations should be thread-safe if evaluated asynchronously.
- */
@FunctionalInterface
public interface PermissionEvaluator {
- /**
- * Checks whether the given human entity possesses the specified permission.
- *
- * @param entity the entity being checked (non-null)
- * @param permission the permission node (non-null)
- * @return {@code true} if the player has the permission; {@code false} otherwise
- */
boolean has(@NotNull HumanEntity entity, @NotNull String permission);
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/RenderContext.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/RenderContext.java
index 1369aa4..f34a6ef 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/RenderContext.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/RenderContext.java
@@ -4,29 +4,12 @@
import org.bukkit.permissions.Permissible;
import org.jetbrains.annotations.NotNull;
-/**
- * Immutable context used during GUI item rendering.
- *
- * Encapsulates the viewer and the permission evaluation strategy,
- * ensuring renderers remain stateless and easily testable.
- *
- * Thread-safety: This record is immutable and thread-safe
- * as long as the underlying {@link PermissionEvaluator} implementation is thread-safe.
- *
- * @param viewer the player for whom the GUI is being rendered
- * @param permissionEvaluator the strategy used to check permissions
- */
public record RenderContext(
@NotNull Player viewer,
@NotNull PermissionEvaluator permissionEvaluator
) {
- /**
- * Creates a default context that checks if player has permission.
- *
- * @return the default {@link RenderContext} instance
- */
- public static @NotNull RenderContext defaultContext(@NotNull Player viewer) {
+ public static RenderContext defaultContext(@NotNull Player viewer) {
return new RenderContext(viewer, Permissible::hasPermission);
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/RenderOptions.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/RenderOptions.java
index 03a8d30..ccfaffa 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/RenderOptions.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/RenderOptions.java
@@ -5,36 +5,16 @@
import java.util.function.Consumer;
-/**
- * Rendering options that define how permission handling
- * and denied interactions are processed during GUI rendering.
- *
- * @param policy how to handle items when the viewer lacks permission
- * @param onDenied consumer called when a denied item is clicked
- *
- * Thread-safety: This record is immutable and thread-safe,
- * provided that the supplied {@link Consumer} implementation is thread-safe.
- */
public record RenderOptions(
@NotNull NoPermissionPolicy policy,
@NotNull Consumer onDenied
) {
- /**
- * Creates a default option that disables unauthorized items silently.
- *
- * @return the default {@link RenderOptions} instance
- */
- public static @NotNull RenderOptions defaultDenySilently() {
+ public static RenderOptions defaultDenySilently() {
return new RenderOptions(NoPermissionPolicy.DISABLE, e -> {});
}
- /**
- * Creates a default option that hides unauthorized items completely.
- *
- * @return the default {@link RenderOptions} instance
- */
- public static @NotNull RenderOptions defaultHide() {
+ public static RenderOptions defaultHide() {
return new RenderOptions(NoPermissionPolicy.HIDE, e -> {});
}
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/TriumphGuiRenderer.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/TriumphGuiRenderer.java
index 5fbbc70..3ce9477 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/TriumphGuiRenderer.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/render/TriumphGuiRenderer.java
@@ -2,7 +2,6 @@
import com.github.imdmk.playtime.platform.gui.item.ItemGui;
import com.github.imdmk.playtime.platform.gui.item.ItemGuiTransformer;
-import com.github.imdmk.playtime.shared.validate.Validator;
import dev.triumphteam.gui.builder.item.BaseItemBuilder;
import dev.triumphteam.gui.components.GuiAction;
import dev.triumphteam.gui.guis.BaseGui;
@@ -12,117 +11,64 @@
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
-/**
- * Default {@link GuiRenderer} implementation using the Triumph GUI API.
- *
- * Responsible for rendering {@link ItemGui} objects into a {@link BaseGui},
- * applying permission policies and wiring click handlers.
- *
- *
Behavior:
- *
- * - If {@link NoPermissionPolicy#HIDE} → item is not rendered (returns {@code null}).
- * - If {@link NoPermissionPolicy#DISABLE} → click is blocked (cancelled) silently.
- * - Otherwise → executes provided click handler.
- *
- */
public final class TriumphGuiRenderer implements GuiRenderer {
- /**
- * Creates a new renderer instance.
- * Renderer is stateless and may be safely reused.
- *
- * @return new {@link TriumphGuiRenderer} instance
- */
public static TriumphGuiRenderer newRenderer() {
return new TriumphGuiRenderer();
}
- /**
- * Places a rendered {@link ItemGui} into the specified GUI slot.
- * If the item should be hidden (policy {@code HIDE}), it will not be placed.
- *
- * @param gui target GUI
- * @param slot target slot index
- * @param item GUI item definition
- * @param context render context
- * @param options render options
- * @param onClick click action to execute if allowed
- * @param builderEditor optional builder customization
- */
@Override
@Contract(mutates = "param1")
public void setItem(
- @NotNull final BaseGui gui,
- final int slot,
- @NotNull final ItemGui item,
- @NotNull final RenderContext context,
- @NotNull final RenderOptions options,
- @NotNull final Consumer onClick,
- @NotNull final Consumer> builderEditor
+ @NotNull BaseGui gui,
+ int slot,
+ @NotNull ItemGui item,
+ @NotNull RenderContext context,
+ @NotNull RenderOptions options,
+ @NotNull Consumer onClick,
+ @NotNull Consumer> builderEditor
) {
- validateArgs(gui, item, context, options, onClick, builderEditor);
-
- final GuiItem guiItem = buildGuiItem(item, context, options, onClick, builderEditor);
- if (guiItem != null) {
- gui.setItem(slot, guiItem);
+ final GuiItem builtItem = buildGuiItem(item, context, options, onClick, builderEditor);
+ if (builtItem != null) {
+ gui.setItem(slot, builtItem);
}
}
- /**
- * Adds a rendered {@link ItemGui} to the GUI at the next available position.
- * If the item should be hidden (policy {@code HIDE}), it will not be added.
- *
- * @param gui target GUI
- * @param item GUI item definition
- * @param context render context
- * @param options render options
- * @param onClick click action to execute if allowed
- * @param builderEditor optional builder customization
- */
@Override
@Contract(mutates = "param1")
public void addItem(
- @NotNull final BaseGui gui,
- @NotNull final ItemGui item,
- @NotNull final RenderContext context,
- @NotNull final RenderOptions options,
- @NotNull final Consumer onClick,
- @NotNull final Consumer> builderEditor
+ @NotNull BaseGui gui,
+ @NotNull ItemGui item,
+ @NotNull RenderContext context,
+ @NotNull RenderOptions options,
+ @NotNull Consumer onClick,
+ @NotNull Consumer> builderEditor
) {
- validateArgs(gui, item, context, options, onClick, builderEditor);
-
- final GuiItem guiItem = buildGuiItem(item, context, options, onClick, builderEditor);
- if (guiItem != null) {
- gui.addItem(guiItem);
+ final GuiItem builtItem = buildGuiItem(item, context, options, onClick, builderEditor);
+ if (builtItem != null) {
+ gui.addItem(builtItem);
}
}
- /**
- * Builds a {@link GuiItem} based on the given item definition and context.
- *
- * Permission logic:
- *
- * - If the viewer lacks permission and policy is {@code HIDE}, returns {@code null}.
- * - If the viewer lacks permission and policy is {@code DISABLE}, click is blocked silently.
- *
- *
- * @return a built {@link GuiItem}, or {@code null} if hidden
- */
- private @Nullable GuiItem buildGuiItem(
- @NotNull final ItemGui item,
- @NotNull final RenderContext context,
- @NotNull final RenderOptions options,
- @NotNull final Consumer onClick,
- @NotNull final Consumer> builderEditor
+ private static GuiItem buildGuiItem(
+ ItemGui item,
+ RenderContext context,
+ RenderOptions options,
+ Consumer onClick,
+ Consumer> builderEditor
) {
final String requiredPerm = item.requiredPermission();
+ final boolean allowedForViewerNow = hasPermission(requiredPerm, context, context.viewer());
+ if (!allowedForViewerNow && options.policy() == NoPermissionPolicy.HIDE) {
+ return null;
+ }
+
final GuiAction clickHandler = event -> {
- if (!has(requiredPerm, context, event.getWhoClicked())) {
+ if (!hasPermission(requiredPerm, context, event.getWhoClicked())) {
event.setCancelled(true);
event.setResult(Event.Result.DENY);
options.onDenied().accept(event);
@@ -132,46 +78,10 @@ public void addItem(
onClick.accept(event);
};
- final boolean allowedForViewerNow = has(requiredPerm, context, context.viewer());
- if (!allowedForViewerNow && options.policy() == NoPermissionPolicy.HIDE) {
- return null;
- }
-
return ItemGuiTransformer.toGuiItem(item, clickHandler, builderEditor);
}
- /**
- * Checks if the given entity has the required permission.
- *
- * @param permission permission string or {@code null}
- * @param context render context
- * @param entity entity to check
- * @return {@code true} if allowed, otherwise {@code false}
- */
- private static boolean has(@Nullable final String permission,
- @NotNull final RenderContext context,
- @NotNull final HumanEntity entity) {
+ private static boolean hasPermission(String permission, RenderContext context, HumanEntity entity) {
return permission == null || context.permissionEvaluator().has(entity, permission);
}
-
- /**
- * Ensures all arguments are non-null.
- *
- * @throws NullPointerException if any argument is {@code null}
- */
- private static void validateArgs(
- final BaseGui gui,
- final ItemGui item,
- final RenderContext context,
- final RenderOptions options,
- final Consumer onClick,
- final Consumer> builderEditor
- ) {
- Validator.notNull(gui, "gui cannot be null");
- Validator.notNull(item, "item cannot be null");
- Validator.notNull(context, "context cannot be null");
- Validator.notNull(options, "options cannot be null");
- Validator.notNull(onClick, "onClick cannot be null");
- Validator.notNull(builderEditor, "builderEditor cannot be null");
- }
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/AbstractGui.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/AbstractGui.java
index 17d6264..2a6599b 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/AbstractGui.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/AbstractGui.java
@@ -1,12 +1,9 @@
package com.github.imdmk.playtime.platform.gui.view;
-import com.github.imdmk.playtime.platform.gui.config.GuiConfig;
import com.github.imdmk.playtime.platform.gui.config.NavigationBarConfig;
import com.github.imdmk.playtime.platform.gui.render.GuiRenderer;
-import com.github.imdmk.playtime.platform.gui.render.RenderContext;
import com.github.imdmk.playtime.platform.gui.render.RenderOptions;
import com.github.imdmk.playtime.platform.scheduler.TaskScheduler;
-import com.github.imdmk.playtime.shared.validate.Validator;
import dev.triumphteam.gui.guis.BaseGui;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
@@ -14,18 +11,6 @@
import java.util.function.Consumer;
-/**
- * Thin base for GUI implementations.
- *
- * Responsibilities:
- *
- * - Provide navigation helpers (Next/Previous/Exit),
- * - Hold shared collaborators: {@link GuiConfig}, {@link TaskScheduler},
- * {@link GuiRenderer}, {@link RenderContext}, {@link RenderOptions}.
- *
- *
- * Threading: All methods are expected to be called on the Bukkit main thread.
- */
public abstract class AbstractGui {
protected final NavigationBarConfig config;
@@ -35,22 +20,16 @@ public abstract class AbstractGui {
private final NavigationBar navigationBar;
- /**
- * @param config GUI config (visual defaults, nav items, etc.)
- * @param taskScheduler scheduler for short, sync GUI updates
- * @param renderer renderer that places items and enforces permission policy
- * @param renderOptions render options (no-permission policy, onDenied)
- */
protected AbstractGui(
@NotNull NavigationBarConfig config,
@NotNull TaskScheduler taskScheduler,
@NotNull GuiRenderer renderer,
@NotNull RenderOptions renderOptions
) {
- this.config = Validator.notNull(config, "config cannot be null");
- this.scheduler = Validator.notNull(taskScheduler, "taskScheduler cannot be null");
- this.renderer = Validator.notNull(renderer, "renderer cannot be null");
- this.renderOptions = Validator.notNull(renderOptions, "renderOptions cannot be null");
+ this.config = config;
+ this.scheduler = taskScheduler;
+ this.renderer = renderer;
+ this.renderOptions = renderOptions;
this.navigationBar = new NavigationBar(
this.config,
@@ -60,44 +39,15 @@ protected AbstractGui(
);
}
- /**
- * Places the "Next" control if the GUI is paginated.
- *
- * @param gui target GUI
- * @param viewer target viewer
- */
protected void placeNext(@NotNull BaseGui gui, @NotNull Player viewer) {
- Validator.notNull(gui, "gui cannot be null");
- Validator.notNull(viewer, "viewer cannot be null");
navigationBar.setNext(gui, viewer);
}
- /**
- * Places the "Previous" control if the GUI is paginated.
- *
- * @param gui target GUI
- * @param viewer target viewer
- */
protected void placePrevious(@NotNull BaseGui gui, @NotNull Player viewer) {
- Validator.notNull(gui, "gui cannot be null");
- Validator.notNull(viewer, "viewer cannot be null");
navigationBar.setPrevious(gui, viewer);
}
- /**
- * Places the "Exit" control.
- *
- * @param gui target GUI
- * @param viewer target viewer
- * @param exit action to run on click
- */
- protected void placeExit(
- @NotNull BaseGui gui,
- @NotNull Player viewer,
- @NotNull Consumer exit) {
- Validator.notNull(gui, "gui cannot be null");
- Validator.notNull(exit, "exit cannot be null");
- Validator.notNull(viewer, "viewer cannot be null");
+ protected void placeExit(@NotNull BaseGui gui, @NotNull Player viewer, @NotNull Consumer exit) {
navigationBar.setExit(gui, viewer, exit);
}
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/GridSlots.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/GridSlots.java
index 5558fb9..5b604fb 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/GridSlots.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/GridSlots.java
@@ -1,12 +1,5 @@
package com.github.imdmk.playtime.platform.gui.view;
-/**
- * Provides predefined slot positions for common GUI navigation controls
- * (Next, Previous, Exit) depending on the GUI height (3–6 rows).
- *
- * Each constant represents the index of an inventory slot where
- * navigation buttons should be placed.
- */
final class GridSlots {
private static final int ROW_3_NEXT = 25;
@@ -29,12 +22,6 @@ private GridSlots() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated.");
}
- /**
- * Returns the inventory slot index for the "Next Page" button.
- *
- * @param rows number of GUI rows (3–6)
- * @return slot index for the next-page control
- */
static int next(int rows) {
return switch (rows) {
case 3 -> ROW_3_NEXT;
@@ -45,12 +32,6 @@ static int next(int rows) {
};
}
- /**
- * Returns the inventory slot index for the "Previous Page" button.
- *
- * @param rows number of GUI rows (3–6)
- * @return slot index for the previous-page control
- */
static int previous(int rows) {
return switch (rows) {
case 3 -> ROW_3_PREVIOUS;
@@ -61,12 +42,6 @@ static int previous(int rows) {
};
}
- /**
- * Returns the inventory slot index for the "Exit" button.
- *
- * @param rows number of GUI rows (3–6)
- * @return slot index for the exit control
- */
static int exit(int rows) {
return switch (rows) {
case 3 -> ROW_3_EXIT;
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/GuiOpener.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/GuiOpener.java
index 4670266..d625b14 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/GuiOpener.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/GuiOpener.java
@@ -1,136 +1,101 @@
package com.github.imdmk.playtime.platform.gui.view;
+import com.github.imdmk.playtime.injector.annotations.Service;
import com.github.imdmk.playtime.platform.gui.GuiRegistry;
import com.github.imdmk.playtime.platform.gui.IdentifiableGui;
import com.github.imdmk.playtime.platform.scheduler.TaskScheduler;
-import com.github.imdmk.playtime.shared.validate.Validator;
import dev.triumphteam.gui.guis.BaseGui;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.panda_lang.utilities.inject.annotations.Inject;
-/**
- * Opens GUIs by id or class on the Bukkit main thread.
- *
- *
Responsibilities:
- *
- * - Lookup GUIs via {@link GuiRegistry},
- * - Invoke {@code BaseGui#open(Player)} on the main thread using {@link TaskScheduler}.
- *
- *
- * Thread-safety: Safe to call from any thread. Actual GUI operations are marshalled to the main thread.
- */
+@Service
public final class GuiOpener {
private final GuiRegistry registry;
- private final TaskScheduler taskScheduler;
+ private final TaskScheduler scheduler;
@Inject
- public GuiOpener(@NotNull GuiRegistry registry, @NotNull TaskScheduler taskScheduler) {
- this.registry = Validator.notNull(registry, "registry cannot be null");
- this.taskScheduler = Validator.notNull(taskScheduler, "taskScheduler cannot be null");
+ public GuiOpener(@NotNull GuiRegistry registry, @NotNull TaskScheduler scheduler) {
+ this.registry = registry;
+ this.scheduler = scheduler;
}
- /**
- * Opens a non-parameterized GUI by its concrete class.
- *
- * @throws IllegalArgumentException if GUI is not registered or not a {@link SimpleGui}
- */
public void open(
@NotNull Class extends SimpleGui> type,
- @NotNull Player viewer) {
- Validator.notNull(type, "type cannot be null");
- Validator.notNull(viewer, "viewer cannot be null");
-
- IdentifiableGui gui = require(type);
+ @NotNull Player viewer
+ ) {
+ final IdentifiableGui gui = require(type);
if (!(gui instanceof SimpleGui simpleGui)) {
throw wrongType(type.getName(), gui, "SimpleGui");
}
- BaseGui baseGui = simpleGui.createGui();
+ final BaseGui baseGui = simpleGui.createGui();
simpleGui.prepareItems(baseGui, viewer);
- taskScheduler.runSync(() -> baseGui.open(viewer));
+ scheduler.runSync(() -> baseGui.open(viewer));
}
- /**
- * Opens a parameterized GUI by its concrete class.
- *
- * @throws IllegalArgumentException if GUI is not registered or not a {@link ParameterizedGui}
- */
@SuppressWarnings("unchecked")
- public void open(@NotNull Class extends ParameterizedGui> type,
- @NotNull Player viewer,
- @NotNull T parameter) {
- Validator.notNull(type, "type cannot be null");
- Validator.notNull(viewer, "viewer cannot be null");
- Validator.notNull(parameter, "parameter cannot be null");
-
- IdentifiableGui gui = require(type);
+ public void open(
+ @NotNull Class extends ParameterizedGui> type,
+ @NotNull Player viewer,
+ @NotNull T parameter
+ ) {
+ final IdentifiableGui gui = require(type);
if (!(gui instanceof ParameterizedGui> paramGui)) {
throw wrongType(type.getName(), gui, "ParameterizedGui");
}
- ParameterizedGui typed = (ParameterizedGui) paramGui;
- BaseGui baseGui = typed.createGui(viewer, parameter);
+ final ParameterizedGui typed = (ParameterizedGui) paramGui;
+ final BaseGui baseGui = typed.createGui(viewer, parameter);
+
typed.prepareItems(baseGui, viewer, parameter);
- taskScheduler.runSync(() -> baseGui.open(viewer));
+ scheduler.runSync(() -> baseGui.open(viewer));
}
- /**
- * Opens a non-parameterized GUI by id for the given player.
- *
- * @throws IllegalArgumentException if id is unknown or GUI is not a {@link SimpleGui}
- */
+
public void open(
@NotNull String id,
- @NotNull Player viewer) {
- Validator.notNull(id, "id cannot be null");
- Validator.notNull(viewer, "viewer cannot be null");
-
- IdentifiableGui gui = require(id);
+ @NotNull Player viewer
+ ) {
+ final IdentifiableGui gui = require(id);
if (!(gui instanceof SimpleGui simpleGui)) {
throw wrongType(id, gui, "SimpleGui");
}
- BaseGui baseGui = simpleGui.createGui();
+ final BaseGui baseGui = simpleGui.createGui();
+
simpleGui.prepareItems(baseGui, viewer);
- taskScheduler.runSync(() -> baseGui.open(viewer));
+ scheduler.runSync(() -> baseGui.open(viewer));
}
- /**
- * Opens a parameterized GUI by id for the given player.
- *
- * @throws IllegalArgumentException if id is unknown or GUI is not a {@link ParameterizedGui}
- */
@SuppressWarnings("unchecked")
public void open(
@NotNull String id,
@NotNull Player viewer,
- @NotNull T parameter) {
- Validator.notNull(id, "id cannot be null");
- Validator.notNull(viewer, "viewer cannot be null");
- Validator.notNull(parameter, "parameter cannot be null");
-
- IdentifiableGui gui = require(id);
+ @NotNull T parameter
+ ) {
+ final IdentifiableGui gui = require(id);
if (!(gui instanceof ParameterizedGui> paramGui)) {
throw wrongType(id, gui, "ParameterizedGui");
}
- ParameterizedGui typed = (ParameterizedGui) paramGui;
- BaseGui baseGui = typed.createGui(viewer, parameter);
+ final ParameterizedGui typed = (ParameterizedGui) paramGui;
+ final BaseGui baseGui = typed.createGui(viewer, parameter);
+
typed.prepareItems(baseGui, viewer, parameter);
- taskScheduler.runSync(() -> baseGui.open(viewer));
+ scheduler.runSync(() -> baseGui.open(viewer));
}
- private @NotNull IdentifiableGui require(@NotNull String id) {
- IdentifiableGui gui = registry.getById(id);
+ private IdentifiableGui require(String id) {
+ final IdentifiableGui gui = registry.getById(id);
if (gui == null) {
throw new IllegalArgumentException("No GUI registered under id '" + id + "'");
}
return gui;
}
- private @NotNull IdentifiableGui require(@NotNull Class extends IdentifiableGui> type) {
- IdentifiableGui gui = registry.getByClass(type);
+ private IdentifiableGui require(Class extends IdentifiableGui> type) {
+ final IdentifiableGui gui = registry.getByClass(type);
if (gui == null) {
throw new IllegalArgumentException("No GUI registered for class '" + type.getName() + "'");
}
diff --git a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/NavigationBar.java b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/NavigationBar.java
index 843cd10..9d330b4 100644
--- a/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/NavigationBar.java
+++ b/playtime-core/src/main/java/com/github/imdmk/playtime/platform/gui/view/NavigationBar.java
@@ -5,7 +5,6 @@
import com.github.imdmk.playtime.platform.gui.render.RenderContext;
import com.github.imdmk.playtime.platform.gui.render.RenderOptions;
import com.github.imdmk.playtime.platform.scheduler.TaskScheduler;
-import com.github.imdmk.playtime.shared.validate.Validator;
import dev.triumphteam.gui.guis.BaseGui;
import dev.triumphteam.gui.guis.PaginatedGui;
import org.bukkit.entity.Player;
@@ -15,116 +14,75 @@
import java.time.Duration;
import java.util.function.Consumer;
-/**
- * Places navigation controls (Next, Previous, Exit) into Triumph GUIs.
- *