Add Javadocs

This commit is contained in:
2026-05-19 19:21:18 -04:00
parent 66476fe110
commit d58365f93f
35 changed files with 1199 additions and 0 deletions
@@ -6,6 +6,8 @@ package dev.plex.api;
public interface ApiCompatibility
{
/**
* Returns the module API compatibility version.
*
* @return the provided module API compatibility version
*/
int version();
@@ -22,37 +22,93 @@ import dev.plex.api.storage.StorageApi;
public interface PlexApi
{
/**
* Returns module API compatibility information for this Plex build.
*
* @return module API compatibility information for this Plex build
*/
ApiCompatibility compatibility();
/**
* Returns access to shared Plex configuration files.
*
* @return safe access to shared Plex configuration files
*/
ConfigurationApi configuration();
/**
* Returns access to module metadata and module-related operations.
*
* @return safe access to module metadata and module-related operations
*/
ModulesApi modules();
/**
* Returns command registration operations.
*
* @return command registration operations for Plex commands
*/
CommandApi commands();
/**
* Returns listener registration operations.
*
* @return listener registration operations for Bukkit listeners
*/
ListenerApi listeners();
/**
* Returns module configuration creation operations.
*
* @return module configuration creation operations
*/
ModuleConfigApi moduleConfigs();
/**
* Returns logging operations.
*
* @return Plex logging operations
*/
LoggingApi logging();
/**
* Returns message formatting and broadcast operations.
*
* @return message formatting and broadcast operations
*/
MessageApi messages();
/**
* Returns player lookup operations.
*
* @return player lookup operations
*/
PlayersApi players();
/**
* Returns punishment lookup and creation operations.
*
* @return punishment lookup and creation operations
*/
PunishmentsApi punishments();
/**
* Returns CoreProtect rollback operations.
*
* @return CoreProtect rollback operations
*/
RollbackApi rollback();
/**
* Returns Paper and Folia scheduler operations.
*
* @return Paper and Folia scheduler operations
*/
SchedulerApi scheduler();
/**
* Returns SQL storage access operations.
*
* @return SQL storage access operations
*/
StorageApi storage();
}
@@ -2,9 +2,22 @@ package dev.plex.api.command;
import dev.plex.command.PlexCommand;
/**
* Registers and unregisters Plex commands with the running platform.
*/
public interface CommandApi
{
/**
* Registers a command with Plex.
*
* @param command command to register
*/
void register(PlexCommand command);
/**
* Unregisters a command from Plex.
*
* @param command command to unregister
*/
void unregister(PlexCommand command);
}
@@ -5,11 +5,31 @@ package dev.plex.api.config;
*/
public interface ConfigurationApi
{
/**
* Returns the main Plex configuration.
*
* @return the main Plex configuration
*/
PlexConfiguration mainConfig();
/**
* Returns the shared message configuration.
*
* @return the shared message configuration
*/
PlexConfiguration messages();
/**
* Returns the indefinite ban configuration.
*
* @return the indefinite ban configuration
*/
PlexConfiguration indefiniteBans();
/**
* Returns the toggle configuration.
*
* @return the toggle configuration
*/
PlexConfiguration toggles();
}
@@ -2,7 +2,18 @@ package dev.plex.api.config;
import dev.plex.module.PlexModule;
/**
* Creates configuration files owned by Plex modules.
*/
public interface ModuleConfigApi
{
/**
* Creates or opens a module configuration.
*
* @param module module that owns the configuration
* @param from resource path to copy defaults from
* @param to destination file path relative to the module data folder
* @return module configuration wrapper
*/
ModuleConfiguration create(PlexModule module, String from, String to);
}
@@ -2,8 +2,25 @@ package dev.plex.api.config;
import org.bukkit.configuration.file.YamlConfiguration;
/**
* Mutable YAML configuration owned by a Plex module.
*/
public abstract class ModuleConfiguration extends YamlConfiguration
{
/**
* Creates a module configuration.
*/
public ModuleConfiguration()
{
}
/**
* Loads the configuration from disk, merging defaults when the implementation supports it.
*/
public abstract void load();
/**
* Saves the configuration to disk.
*/
public abstract void save();
}
@@ -7,25 +7,92 @@ import java.util.List;
*/
public interface PlexConfiguration
{
/**
* Reads a string value.
*
* @param path configuration path
* @return configured string, or {@code null} if absent
*/
String getString(String path);
/**
* Reads a string value with a fallback.
*
* @param path configuration path
* @param fallback value returned when the path is absent
* @return configured string or fallback
*/
String getString(String path, String fallback);
/**
* Reads a boolean value.
*
* @param path configuration path
* @return configured boolean, or the underlying configuration default
*/
boolean getBoolean(String path);
/**
* Reads a boolean value with a fallback.
*
* @param path configuration path
* @param fallback value returned when the path is absent
* @return configured boolean or fallback
*/
boolean getBoolean(String path, boolean fallback);
/**
* Reads an integer value.
*
* @param path configuration path
* @return configured integer, or the underlying configuration default
*/
int getInt(String path);
/**
* Reads an integer value with a fallback.
*
* @param path configuration path
* @param fallback value returned when the path is absent
* @return configured integer or fallback
*/
int getInt(String path, int fallback);
/**
* Reads a string list.
*
* @param path configuration path
* @return configured string list
*/
List<String> getStringList(String path);
/**
* Reads a string list with a fallback.
*
* @param path configuration path
* @param fallback value returned when the path is absent
* @return configured string list or fallback
*/
List<String> getStringList(String path, List<String> fallback);
/**
* Sets a configuration value.
*
* @param path configuration path
* @param value value to write
*/
void set(String path, Object value);
/**
* Sets comments above a configuration path.
*
* @param path configuration path
* @param comments comments to write
*/
void setComments(String path, List<String> comments);
/**
* Saves pending configuration changes to disk.
*/
void save();
}
@@ -2,9 +2,22 @@ package dev.plex.api.listener;
import org.bukkit.event.Listener;
/**
* Registers and unregisters Bukkit event listeners for modules.
*/
public interface ListenerApi
{
/**
* Registers a listener with Plex.
*
* @param listener listener to register
*/
void register(Listener listener);
/**
* Unregisters a listener from Bukkit handler lists.
*
* @param listener listener to unregister
*/
void unregister(Listener listener);
}
@@ -1,9 +1,39 @@
package dev.plex.api.logging;
/**
* Logging facade exposed through the Plex API.
*/
public interface LoggingApi
{
/**
* Writes an informational log message.
*
* @param message message template
* @param args template arguments
*/
void info(String message, Object... args);
/**
* Writes a debug log message.
*
* @param message message template
* @param args template arguments
*/
void debug(String message, Object... args);
/**
* Writes a warning log message.
*
* @param message message template
* @param args template arguments
*/
void warn(String message, Object... args);
/**
* Writes an error log message.
*
* @param message message template
* @param args template arguments
*/
void error(String message, Object... args);
}
@@ -3,13 +3,64 @@ package dev.plex.api.message;
import java.util.List;
import net.kyori.adventure.text.Component;
/**
* Formats configured messages and broadcasts Adventure components.
*/
public interface MessageApi
{
/**
* Resolves a configured message entry into a component.
*
* @param entry message key
* @param objects replacement values
* @return resolved component
*/
Component messageComponent(String entry, Object... objects);
/**
* Resolves a configured message entry into a component using component replacements.
*
* @param entry message key
* @param objects component replacement values
* @return resolved component
*/
Component messageComponent(String entry, Component... objects);
/**
* Resolves a configured message entry into a plain string.
*
* @param entry message key
* @param objects replacement values
* @return resolved message string
*/
String messageString(String entry, Object... objects);
/**
* Deserializes MiniMessage input into a component.
*
* @param input MiniMessage input
* @return deserialized component
*/
Component miniMessage(String input);
/**
* Broadcasts a MiniMessage string to online players.
*
* @param miniMessage MiniMessage input to broadcast
*/
void broadcast(String miniMessage);
/**
* Broadcasts a component to online players.
*
* @param component component to broadcast
*/
void broadcast(Component component);
/**
* Returns the names of currently online players.
*
* @return names of currently online players
*/
List<String> onlinePlayerNames();
}
@@ -11,6 +11,8 @@ import java.util.Optional;
public interface ModulesApi
{
/**
* Returns metadata for all currently discovered modules.
*
* @return immutable metadata for all currently discovered modules
*/
Collection<PlexModuleFile> loadedModules();
@@ -4,9 +4,31 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
/**
* Looks up Plex players through read-only API views.
*/
public interface PlayersApi
{
/**
* Looks up a player by UUID.
*
* @param uuid player UUID
* @return player view, if known
*/
Optional<? extends PlexPlayerView> byUuid(UUID uuid);
/**
* Looks up a player by name.
*
* @param name player name
* @return player view, if known
*/
Optional<? extends PlexPlayerView> byName(String name);
/**
* Returns the names of currently online players.
*
* @return names of currently online players
*/
List<String> onlineNames();
}
@@ -5,14 +5,64 @@ import java.util.UUID;
import dev.plex.api.punishment.PunishmentView;
import org.bukkit.entity.Player;
/**
* Read-only view of a Plex player.
*/
public interface PlexPlayerView
{
/**
* Returns the player's UUID.
*
* @return player UUID
*/
UUID uuid();
/**
* Returns the current or last known player name.
*
* @return current or last known player name
*/
String name();
/**
* Returns known IP addresses.
*
* @return immutable copy of known IP addresses
*/
List<String> ips();
/**
* Returns the player's punishment history.
*
* @return punishment history for the player
*/
List<? extends PunishmentView> punishments();
/**
* Returns whether the player is currently frozen.
*
* @return whether the player is currently frozen
*/
boolean frozen();
/**
* Returns whether the player is currently muted.
*
* @return whether the player is currently muted
*/
boolean muted();
/**
* Returns whether the player is currently locked up.
*
* @return whether the player is currently locked up
*/
boolean lockedUp();
/**
* Returns the Bukkit player instance.
*
* @return Bukkit player instance, or {@code null} when the player is offline
*/
Player bukkitPlayer();
}
@@ -3,10 +3,36 @@ package dev.plex.api.punishment;
import java.util.List;
import java.util.UUID;
/**
* Read-only view of an indefinite ban entry.
*/
public interface IndefiniteBanView
{
/**
* Returns usernames covered by the ban.
*
* @return usernames covered by the ban
*/
List<String> usernames();
/**
* Returns UUIDs covered by the ban.
*
* @return UUIDs covered by the ban
*/
List<UUID> uuids();
/**
* Returns IP addresses covered by the ban.
*
* @return IP addresses covered by the ban
*/
List<String> ips();
/**
* Returns the ban reason.
*
* @return ban reason
*/
String reason();
}
@@ -3,6 +3,20 @@ package dev.plex.api.punishment;
import java.time.ZonedDateTime;
import java.util.UUID;
/**
* Request payload used to create a punishment for a player.
*
* @param punished UUID of the player being punished
* @param punisher UUID of the actor issuing the punishment
* @param punisherName display name of the actor issuing the punishment
* @param ip IP address associated with the punished player
* @param punishedUsername username of the punished player
* @param type punishment type to apply
* @param reason punishment reason
* @param customTime whether the punishment uses a custom duration
* @param active whether the punishment should start active
* @param endDate punishment end date, or {@code null} for punishments without an end date
*/
public record PunishmentRequest(UUID punished, UUID punisher, String punisherName, String ip,
String punishedUsername, PunishmentType type, String reason,
boolean customTime, boolean active, ZonedDateTime endDate)
@@ -1,11 +1,37 @@
package dev.plex.api.punishment;
/**
* Supported punishment types exposed through the API.
*/
public enum PunishmentType
{
/**
* Prevents chat or other messaging actions.
*/
MUTE,
/**
* Freezes player movement.
*/
FREEZE,
/**
* Permanently bans a player.
*/
BAN,
/**
* Temporarily bans a player until an end date.
*/
TEMPBAN,
/**
* Kicks a player from the server.
*/
KICK,
/**
* Applies the smite action to a player.
*/
SMITE
}
@@ -3,17 +3,85 @@ package dev.plex.api.punishment;
import java.time.ZonedDateTime;
import java.util.UUID;
/**
* Read-only view of a Plex punishment.
*/
public interface PunishmentView
{
/**
* Returns the UUID of the punished player.
*
* @return UUID of the punished player
*/
UUID punished();
/**
* Returns the UUID of the actor who issued the punishment.
*
* @return UUID of the actor who issued the punishment
*/
UUID punisher();
/**
* Returns the display name of the actor who issued the punishment.
*
* @return display name of the actor who issued the punishment
*/
String punisherName();
/**
* Returns the IP address associated with the punished player.
*
* @return IP address associated with the punished player
*/
String ip();
/**
* Returns the username of the punished player.
*
* @return username of the punished player
*/
String punishedUsername();
/**
* Returns the punishment type.
*
* @return punishment type
*/
PunishmentType type();
/**
* Returns the punishment reason.
*
* @return punishment reason
*/
String reason();
/**
* Returns whether the punishment uses a custom duration.
*
* @return whether the punishment uses a custom duration
*/
boolean customTime();
/**
* Returns whether the punishment is currently active.
*
* @return whether the punishment is currently active
*/
boolean active();
/**
* Returns the date and time when the punishment was issued.
*
* @return date and time when the punishment was issued
*/
ZonedDateTime issueDate();
/**
* Returns the punishment end date.
*
* @return punishment end date, or {@code null} for punishments without an end date
*/
ZonedDateTime endDate();
}
@@ -5,9 +5,31 @@ import java.util.Optional;
import java.util.UUID;
import dev.plex.api.player.PlexPlayerView;
/**
* Reads and creates Plex punishments.
*/
public interface PunishmentsApi
{
/**
* Returns current indefinite bans.
*
* @return current indefinite bans
*/
List<? extends IndefiniteBanView> indefiniteBans();
/**
* Looks up an indefinite ban by UUID.
*
* @param uuid UUID to look up
* @return matching indefinite ban, if one exists
*/
Optional<? extends IndefiniteBanView> indefiniteBanByUuid(UUID uuid);
/**
* Applies a punishment to a player.
*
* @param player player to punish
* @param punishment punishment details
*/
void punish(PlexPlayerView player, PunishmentRequest punishment);
}
@@ -2,12 +2,35 @@ package dev.plex.api.rollback;
import org.bukkit.command.CommandSender;
/**
* CoreProtect rollback operations exposed to modules.
*/
public interface RollbackApi
{
/**
* Returns whether rollback support is currently available.
*
* @return whether rollback support is currently available
*/
boolean isAvailable();
/**
* Rolls back changes made by a player.
*
* @param sender command sender receiving rollback output
* @param playerName player name to roll back
* @param seconds number of seconds to roll back
* @return {@code true} when the rollback was accepted
*/
boolean rollback(CommandSender sender, String playerName, int seconds);
/**
* Rolls back the last 24 hours of changes made by a player.
*
* @param sender command sender receiving rollback output
* @param playerName player name to roll back
* @return {@code true} when the rollback was accepted
*/
default boolean rollbackLastDay(CommandSender sender, String playerName)
{
return rollback(sender, playerName, 86400);
@@ -11,12 +11,17 @@ import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.Nullable;
/**
* Scheduling facade for Paper and Folia-safe task execution.
*/
public interface SchedulerApi
{
/**
* Executor backed by Paper's async scheduler.
* Use it for blocking I/O and CPU work that does not touch Bukkit world,
* entity, inventory, or command state.
*
* @return async scheduler executor
*/
Executor asyncExecutor();
@@ -25,16 +30,27 @@ public interface SchedulerApi
* Use the global region for state owned by Folia's global region, such as
* console command dispatch, world time, weather, game rules, and plugin-level
* coordination work.
*
* @param task task to execute
*/
void executeGlobal(Runnable task);
/**
* Runs work on the next global-region tick.
*
* @param task task consumer receiving the scheduled task
* @return scheduled task handle
* @see #executeGlobal(Runnable)
*/
ScheduledTask runGlobal(Consumer<ScheduledTask> task);
/**
* Runs work on the next global-region tick.
*
* @param task task to run
* @return scheduled task handle
* @see #runGlobal(Consumer)
*/
default ScheduledTask runGlobal(Runnable task)
{
return runGlobal(scheduledTask -> task.run());
@@ -43,10 +59,21 @@ public interface SchedulerApi
/**
* Runs work on the global region after a tick delay.
*
* @param task task consumer receiving the scheduled task
* @param delayTicks delay in server ticks
* @return scheduled task handle
* @see #executeGlobal(Runnable)
*/
ScheduledTask runGlobalLater(Consumer<ScheduledTask> task, long delayTicks);
/**
* Runs work on the global region after a tick delay.
*
* @param task task to run
* @param delayTicks delay in server ticks
* @return scheduled task handle
* @see #runGlobalLater(Consumer, long)
*/
default ScheduledTask runGlobalLater(Runnable task, long delayTicks)
{
return runGlobalLater(scheduledTask -> task.run(), delayTicks);
@@ -55,10 +82,23 @@ public interface SchedulerApi
/**
* Runs repeating work on the global region.
*
* @param task task consumer receiving the scheduled task
* @param delayTicks initial delay in server ticks
* @param periodTicks repeat interval in server ticks
* @return scheduled task handle
* @see #executeGlobal(Runnable)
*/
ScheduledTask runGlobalTimer(Consumer<ScheduledTask> task, long delayTicks, long periodTicks);
/**
* Runs repeating work on the global region.
*
* @param task task to run
* @param delayTicks initial delay in server ticks
* @param periodTicks repeat interval in server ticks
* @return scheduled task handle
* @see #runGlobalTimer(Consumer, long, long)
*/
default ScheduledTask runGlobalTimer(Runnable task, long delayTicks, long periodTicks)
{
return runGlobalTimer(scheduledTask -> task.run(), delayTicks, periodTicks);
@@ -67,9 +107,19 @@ public interface SchedulerApi
/**
* Runs work on Paper's async scheduler.
* Do not touch Bukkit world, entity, inventory, or command state here.
*
* @param task task consumer receiving the scheduled task
* @return scheduled task handle
*/
ScheduledTask runAsync(Consumer<ScheduledTask> task);
/**
* Runs work on Paper's async scheduler.
*
* @param task task to run
* @return scheduled task handle
* @see #runAsync(Consumer)
*/
default ScheduledTask runAsync(Runnable task)
{
return runAsync(scheduledTask -> task.run());
@@ -78,10 +128,23 @@ public interface SchedulerApi
/**
* Runs async work after a wall-clock delay.
*
* @param task task consumer receiving the scheduled task
* @param delay delay amount
* @param unit delay time unit
* @return scheduled task handle
* @see #runAsync(Consumer)
*/
ScheduledTask runAsyncLater(Consumer<ScheduledTask> task, long delay, TimeUnit unit);
/**
* Runs async work after a wall-clock delay.
*
* @param task task to run
* @param delay delay amount
* @param unit delay time unit
* @return scheduled task handle
* @see #runAsyncLater(Consumer, long, TimeUnit)
*/
default ScheduledTask runAsyncLater(Runnable task, long delay, TimeUnit unit)
{
return runAsyncLater(scheduledTask -> task.run(), delay, unit);
@@ -90,10 +153,25 @@ public interface SchedulerApi
/**
* Runs repeating async work on a wall-clock interval.
*
* @param task task consumer receiving the scheduled task
* @param delay initial delay amount
* @param period repeat interval amount
* @param unit delay and period time unit
* @return scheduled task handle
* @see #runAsync(Consumer)
*/
ScheduledTask runAsyncTimer(Consumer<ScheduledTask> task, long delay, long period, TimeUnit unit);
/**
* Runs repeating async work on a wall-clock interval.
*
* @param task task to run
* @param delay initial delay amount
* @param period repeat interval amount
* @param unit delay and period time unit
* @return scheduled task handle
* @see #runAsyncTimer(Consumer, long, long, TimeUnit)
*/
default ScheduledTask runAsyncTimer(Runnable task, long delay, long period, TimeUnit unit)
{
return runAsyncTimer(scheduledTask -> task.run(), delay, period, unit);
@@ -102,22 +180,41 @@ public interface SchedulerApi
/**
* Executes work on the region that owns the supplied location.
* Use this for block, chunk, and location-bound world access.
*
* @param location location whose owning region should run the task
* @param task task to execute
*/
void executeRegion(Location location, Runnable task);
/**
* Executes work on the region that owns the supplied chunk.
* Use this for block, chunk, and location-bound world access.
*
* @param world world containing the chunk
* @param chunkX chunk X coordinate
* @param chunkZ chunk Z coordinate
* @param task task to execute
*/
void executeRegion(World world, int chunkX, int chunkZ, Runnable task);
/**
* Runs work on the next tick of the region that owns the supplied location.
*
* @param location location whose owning region should run the task
* @param task task consumer receiving the scheduled task
* @return scheduled task handle
* @see #executeRegion(Location, Runnable)
*/
ScheduledTask runRegion(Location location, Consumer<ScheduledTask> task);
/**
* Runs work on the next tick of the region that owns the supplied location.
*
* @param location location whose owning region should run the task
* @param task task to run
* @return scheduled task handle
* @see #runRegion(Location, Consumer)
*/
default ScheduledTask runRegion(Location location, Runnable task)
{
return runRegion(location, scheduledTask -> task.run());
@@ -126,10 +223,25 @@ public interface SchedulerApi
/**
* Runs work on the next tick of the region that owns the supplied chunk.
*
* @param world world containing the chunk
* @param chunkX chunk X coordinate
* @param chunkZ chunk Z coordinate
* @param task task consumer receiving the scheduled task
* @return scheduled task handle
* @see #executeRegion(World, int, int, Runnable)
*/
ScheduledTask runRegion(World world, int chunkX, int chunkZ, Consumer<ScheduledTask> task);
/**
* Runs work on the next tick of the region that owns the supplied chunk.
*
* @param world world containing the chunk
* @param chunkX chunk X coordinate
* @param chunkZ chunk Z coordinate
* @param task task to run
* @return scheduled task handle
* @see #runRegion(World, int, int, Consumer)
*/
default ScheduledTask runRegion(World world, int chunkX, int chunkZ, Runnable task)
{
return runRegion(world, chunkX, chunkZ, scheduledTask -> task.run());
@@ -138,10 +250,23 @@ public interface SchedulerApi
/**
* Runs work on a location's owning region after a tick delay.
*
* @param location location whose owning region should run the task
* @param task task consumer receiving the scheduled task
* @param delayTicks delay in server ticks
* @return scheduled task handle
* @see #executeRegion(Location, Runnable)
*/
ScheduledTask runRegionLater(Location location, Consumer<ScheduledTask> task, long delayTicks);
/**
* Runs work on a location's owning region after a tick delay.
*
* @param location location whose owning region should run the task
* @param task task to run
* @param delayTicks delay in server ticks
* @return scheduled task handle
* @see #runRegionLater(Location, Consumer, long)
*/
default ScheduledTask runRegionLater(Location location, Runnable task, long delayTicks)
{
return runRegionLater(location, scheduledTask -> task.run(), delayTicks);
@@ -150,10 +275,27 @@ public interface SchedulerApi
/**
* Runs work on a chunk's owning region after a tick delay.
*
* @param world world containing the chunk
* @param chunkX chunk X coordinate
* @param chunkZ chunk Z coordinate
* @param task task consumer receiving the scheduled task
* @param delayTicks delay in server ticks
* @return scheduled task handle
* @see #executeRegion(World, int, int, Runnable)
*/
ScheduledTask runRegionLater(World world, int chunkX, int chunkZ, Consumer<ScheduledTask> task, long delayTicks);
/**
* Runs work on a chunk's owning region after a tick delay.
*
* @param world world containing the chunk
* @param chunkX chunk X coordinate
* @param chunkZ chunk Z coordinate
* @param task task to run
* @param delayTicks delay in server ticks
* @return scheduled task handle
* @see #runRegionLater(World, int, int, Consumer, long)
*/
default ScheduledTask runRegionLater(World world, int chunkX, int chunkZ, Runnable task, long delayTicks)
{
return runRegionLater(world, chunkX, chunkZ, scheduledTask -> task.run(), delayTicks);
@@ -162,10 +304,25 @@ public interface SchedulerApi
/**
* Runs repeating work on a location's owning region.
*
* @param location location whose owning region should run the task
* @param task task consumer receiving the scheduled task
* @param delayTicks initial delay in server ticks
* @param periodTicks repeat interval in server ticks
* @return scheduled task handle
* @see #executeRegion(Location, Runnable)
*/
ScheduledTask runRegionTimer(Location location, Consumer<ScheduledTask> task, long delayTicks, long periodTicks);
/**
* Runs repeating work on a location's owning region.
*
* @param location location whose owning region should run the task
* @param task task to run
* @param delayTicks initial delay in server ticks
* @param periodTicks repeat interval in server ticks
* @return scheduled task handle
* @see #runRegionTimer(Location, Consumer, long, long)
*/
default ScheduledTask runRegionTimer(Location location, Runnable task, long delayTicks, long periodTicks)
{
return runRegionTimer(location, scheduledTask -> task.run(), delayTicks, periodTicks);
@@ -174,10 +331,29 @@ public interface SchedulerApi
/**
* Runs repeating work on a chunk's owning region.
*
* @param world world containing the chunk
* @param chunkX chunk X coordinate
* @param chunkZ chunk Z coordinate
* @param task task consumer receiving the scheduled task
* @param delayTicks initial delay in server ticks
* @param periodTicks repeat interval in server ticks
* @return scheduled task handle
* @see #executeRegion(World, int, int, Runnable)
*/
ScheduledTask runRegionTimer(World world, int chunkX, int chunkZ, Consumer<ScheduledTask> task, long delayTicks, long periodTicks);
/**
* Runs repeating work on a chunk's owning region.
*
* @param world world containing the chunk
* @param chunkX chunk X coordinate
* @param chunkZ chunk Z coordinate
* @param task task to run
* @param delayTicks initial delay in server ticks
* @param periodTicks repeat interval in server ticks
* @return scheduled task handle
* @see #runRegionTimer(World, int, int, Consumer, long, long)
*/
default ScheduledTask runRegionTimer(World world, int chunkX, int chunkZ, Runnable task, long delayTicks, long periodTicks)
{
return runRegionTimer(world, chunkX, chunkZ, scheduledTask -> task.run(), delayTicks, periodTicks);
@@ -190,10 +366,23 @@ public interface SchedulerApi
* Paper runs the retired callback if the entity is removed before the task
* can execute.
*
* @param entity entity whose scheduler should run the task
* @param task task to execute
* @param retired callback run if the entity retires before execution
* @param delayTicks delay in server ticks
* @return true if Paper accepted the task
*/
boolean executeEntity(Entity entity, Runnable task, @Nullable Runnable retired, long delayTicks);
/**
* Executes work on the region that currently owns the entity.
*
* @param entity entity whose scheduler should run the task
* @param task task to execute
* @param delayTicks delay in server ticks
* @return {@code true} if Paper accepted the task
* @see #executeEntity(Entity, Runnable, Runnable, long)
*/
default boolean executeEntity(Entity entity, Runnable task, long delayTicks)
{
return executeEntity(entity, task, null, delayTicks);
@@ -202,11 +391,23 @@ public interface SchedulerApi
/**
* Runs work on the next tick of the entity's owning region.
*
* @param entity entity whose scheduler should run the task
* @param task task consumer receiving the scheduled task
* @param retired callback run if the entity retires before execution
* @return scheduled task handle, or {@code null} if the entity is retired
* @see #executeEntity(Entity, Runnable, Runnable, long)
*/
@Nullable
ScheduledTask runEntity(Entity entity, Consumer<ScheduledTask> task, @Nullable Runnable retired);
/**
* Runs work on the next tick of the entity's owning region.
*
* @param entity entity whose scheduler should run the task
* @param task task to run
* @return scheduled task handle, or {@code null} if the entity is retired
* @see #runEntity(Entity, Consumer, Runnable)
*/
default @Nullable ScheduledTask runEntity(Entity entity, Runnable task)
{
return runEntity(entity, scheduledTask -> task.run(), null);
@@ -215,11 +416,25 @@ public interface SchedulerApi
/**
* Runs work on the entity's owning region after a tick delay.
*
* @param entity entity whose scheduler should run the task
* @param task task consumer receiving the scheduled task
* @param retired callback run if the entity retires before execution
* @param delayTicks delay in server ticks
* @return scheduled task handle, or {@code null} if the entity is retired
* @see #executeEntity(Entity, Runnable, Runnable, long)
*/
@Nullable
ScheduledTask runEntityLater(Entity entity, Consumer<ScheduledTask> task, @Nullable Runnable retired, long delayTicks);
/**
* Runs work on the entity's owning region after a tick delay.
*
* @param entity entity whose scheduler should run the task
* @param task task to run
* @param delayTicks delay in server ticks
* @return scheduled task handle, or {@code null} if the entity is retired
* @see #runEntityLater(Entity, Consumer, Runnable, long)
*/
default @Nullable ScheduledTask runEntityLater(Entity entity, Runnable task, long delayTicks)
{
return runEntityLater(entity, scheduledTask -> task.run(), null, delayTicks);
@@ -228,11 +443,27 @@ public interface SchedulerApi
/**
* Runs repeating work on the entity's owning region.
*
* @param entity entity whose scheduler should run the task
* @param task task consumer receiving the scheduled task
* @param retired callback run if the entity retires before execution
* @param delayTicks initial delay in server ticks
* @param periodTicks repeat interval in server ticks
* @return scheduled task handle, or {@code null} if the entity is retired
* @see #executeEntity(Entity, Runnable, Runnable, long)
*/
@Nullable
ScheduledTask runEntityTimer(Entity entity, Consumer<ScheduledTask> task, @Nullable Runnable retired, long delayTicks, long periodTicks);
/**
* Runs repeating work on the entity's owning region.
*
* @param entity entity whose scheduler should run the task
* @param task task to run
* @param delayTicks initial delay in server ticks
* @param periodTicks repeat interval in server ticks
* @return scheduled task handle, or {@code null} if the entity is retired
* @see #runEntityTimer(Entity, Consumer, Runnable, long, long)
*/
default @Nullable ScheduledTask runEntityTimer(Entity entity, Runnable task, long delayTicks, long periodTicks)
{
return runEntityTimer(entity, scheduledTask -> task.run(), null, delayTicks, periodTicks);
@@ -3,13 +3,36 @@ package dev.plex.api.storage;
import java.sql.Connection;
import java.sql.SQLException;
/**
* Provides controlled access to Plex SQL storage.
*/
public interface StorageApi
{
/**
* Opens a SQL connection for the supplied callback and closes it afterwards.
*
* @param function callback that uses the connection
* @param <T> callback result type
* @return callback result
* @throws SQLException if a connection or callback SQL operation fails
*/
<T> T withConnection(SqlFunction<T> function) throws SQLException;
/**
* SQL callback used by {@link #withConnection(SqlFunction)}.
*
* @param <T> callback result type
*/
@FunctionalInterface
interface SqlFunction<T>
{
/**
* Uses a SQL connection.
*
* @param connection open SQL connection
* @return callback result
* @throws SQLException if the callback cannot complete its SQL work
*/
T apply(Connection connection) throws SQLException;
}
}
@@ -13,8 +13,19 @@ import java.util.List;
*/
public interface PlexCommand
{
/**
* Builds the Brigadier command tree for this command.
*
* @return root literal command node
*/
LiteralCommandNode<CommandSourceStack> buildCommand();
/**
* Reads command parameter metadata from {@link CommandParameters}.
*
* @return command parameter metadata
* @throws IllegalStateException if the command class is missing {@link CommandParameters}
*/
default CommandParameters parameters()
{
CommandParameters parameters = getClass().getAnnotation(CommandParameters.class);
@@ -25,6 +36,12 @@ public interface PlexCommand
return parameters;
}
/**
* Reads command permission metadata from {@link CommandPermissions}.
*
* @return command permission metadata
* @throws IllegalStateException if the command class is missing {@link CommandPermissions}
*/
default CommandPermissions permissions()
{
CommandPermissions permissions = getClass().getAnnotation(CommandPermissions.class);
@@ -35,31 +52,61 @@ public interface PlexCommand
return permissions;
}
/**
* Returns the primary command name.
*
* @return primary command name
*/
default String getName()
{
return parameters().name();
}
/**
* Returns the command description.
*
* @return command description
*/
default String getDescription()
{
return parameters().description();
}
/**
* Returns command usage text.
*
* @return command usage text with {@code <command>} replaced by the command name
*/
default String getUsage()
{
return parameters().usage().replace("<command>", getName());
}
/**
* Returns the permission node required to use the command.
*
* @return permission node required to use the command
*/
default String getPermission()
{
return permissions().permission();
}
/**
* Returns the command source required to run the command.
*
* @return command source required to run the command
*/
default RequiredCommandSource getRequiredSource()
{
return permissions().source();
}
/**
* Returns command aliases as a trimmed list.
*
* @return comma-separated aliases from {@link CommandParameters#aliases()} as a trimmed list
*/
default List<String> getAliases()
{
String aliases = parameters().aliases();
@@ -3,11 +3,37 @@ package dev.plex.command.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Declares display and invocation metadata for a Plex command.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandParameters
{
/**
* Returns the primary command name.
*
* @return primary command name
*/
String name();
/**
* Returns the short command description.
*
* @return short command description
*/
String description() default "";
/**
* Returns the command usage text.
*
* @return command usage text; {@code <command>} is replaced with the command name
*/
String usage() default "/<command>";
/**
* Returns comma-separated command aliases.
*
* @return comma-separated command aliases
*/
String aliases() default "";
}
@@ -4,9 +4,23 @@ import dev.plex.command.source.RequiredCommandSource;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Declares permission and command-source requirements for a Plex command.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandPermissions
{
/**
* Returns the permission node required to use the command.
*
* @return permission node required to use the command
*/
String permission() default "";
/**
* Returns the command source required to run the command.
*
* @return command source required to run the command
*/
RequiredCommandSource source() default RequiredCommandSource.ANY;
}
@@ -1,12 +1,23 @@
package dev.plex.command.exception;
/**
* Signals that command execution failed with a user-facing message.
*/
public class CommandFailException extends RuntimeException
{
/**
* Creates an exception with the default command failure marker message.
*/
public CommandFailException()
{
super("CommandFailException");
}
/**
* Creates an exception with a custom user-facing failure message.
*
* @param message failure message
*/
public CommandFailException(String message)
{
super(message);
@@ -1,12 +1,23 @@
package dev.plex.command.exception;
/**
* Signals that the console must supply a target player for a command.
*/
public class ConsoleMustDefinePlayerException extends RuntimeException
{
/**
* Creates an exception with the default console target marker message.
*/
public ConsoleMustDefinePlayerException()
{
super("ConsoleMustDefinePlayerException");
}
/**
* Creates an exception with a custom user-facing message.
*
* @param message failure message
*/
public ConsoleMustDefinePlayerException(String message)
{
super(message);
@@ -1,12 +1,23 @@
package dev.plex.command.exception;
/**
* Signals that a command can only be run from the console.
*/
public class ConsoleOnlyException extends RuntimeException
{
/**
* Creates an exception with the default console-only marker message.
*/
public ConsoleOnlyException()
{
super("ConsoleOnlyException");
}
/**
* Creates an exception with a custom user-facing message.
*
* @param message failure message
*/
public ConsoleOnlyException(String message)
{
super(message);
@@ -1,12 +1,23 @@
package dev.plex.command.exception;
/**
* Signals that a command expected a banned player but none was found.
*/
public class PlayerNotBannedException extends RuntimeException
{
/**
* Creates an exception with the default player-not-banned marker message.
*/
public PlayerNotBannedException()
{
super("PlayerNotBannedException");
}
/**
* Creates an exception with a custom user-facing message.
*
* @param message failure message
*/
public PlayerNotBannedException(String message)
{
super(message);
@@ -1,12 +1,23 @@
package dev.plex.command.exception;
/**
* Signals that a command could not find the requested player.
*/
public class PlayerNotFoundException extends RuntimeException
{
/**
* Creates an exception with the default player-not-found marker message.
*/
public PlayerNotFoundException()
{
super("PlayerNotFoundException");
}
/**
* Creates an exception with a custom user-facing message.
*
* @param message failure message
*/
public PlayerNotFoundException(String message)
{
super(message);
@@ -1,8 +1,22 @@
package dev.plex.command.source;
/**
* Source restrictions for command execution.
*/
public enum RequiredCommandSource
{
/**
* Allows both player and console sources.
*/
ANY,
/**
* Allows only in-game player sources.
*/
IN_GAME,
/**
* Allows only console sources.
*/
CONSOLE
}
@@ -11,11 +11,24 @@ public class ModuleConfig extends ModuleConfiguration
private static Factory factory;
private final ModuleConfiguration delegate;
/**
* Installs the platform factory used to create module configurations.
*
* @param factory module configuration factory
*/
public static void setFactory(Factory factory)
{
ModuleConfig.factory = factory;
}
/**
* Creates or opens a module configuration through the installed platform factory.
*
* @param module module that owns the configuration
* @param from resource path to copy defaults from
* @param to destination file path relative to the module data folder
* @throws IllegalStateException if Plex has not installed a factory yet
*/
public ModuleConfig(PlexModule module, String from, String to)
{
if (factory == null)
@@ -25,99 +38,155 @@ public class ModuleConfig extends ModuleConfiguration
this.delegate = factory.create(module, from, to);
}
/**
* {@inheritDoc}
*/
@Override
public void load()
{
delegate.load();
}
/**
* {@inheritDoc}
*/
@Override
public void save()
{
delegate.save();
}
/**
* {@inheritDoc}
*/
@Override
public Object get(String path)
{
return delegate.get(path);
}
/**
* {@inheritDoc}
*/
@Override
public Object get(String path, Object def)
{
return delegate.get(path, def);
}
/**
* {@inheritDoc}
*/
@Override
public String getString(String path)
{
return delegate.getString(path);
}
/**
* {@inheritDoc}
*/
@Override
public String getString(String path, String def)
{
return delegate.getString(path, def);
}
/**
* {@inheritDoc}
*/
@Override
public int getInt(String path)
{
return delegate.getInt(path);
}
/**
* {@inheritDoc}
*/
@Override
public int getInt(String path, int def)
{
return delegate.getInt(path, def);
}
/**
* {@inheritDoc}
*/
@Override
public boolean getBoolean(String path)
{
return delegate.getBoolean(path);
}
/**
* {@inheritDoc}
*/
@Override
public boolean getBoolean(String path, boolean def)
{
return delegate.getBoolean(path, def);
}
/**
* {@inheritDoc}
*/
@Override
public long getLong(String path)
{
return delegate.getLong(path);
}
/**
* {@inheritDoc}
*/
@Override
public long getLong(String path, long def)
{
return delegate.getLong(path, def);
}
/**
* {@inheritDoc}
*/
@Override
public double getDouble(String path)
{
return delegate.getDouble(path);
}
/**
* {@inheritDoc}
*/
@Override
public double getDouble(String path, double def)
{
return delegate.getDouble(path, def);
}
/**
* {@inheritDoc}
*/
@Override
public void set(String path, Object value)
{
delegate.set(path, value);
}
/**
* Factory installed by the platform to create module configuration delegates.
*/
@FunctionalInterface
public interface Factory
{
/**
* Creates or opens a module configuration.
*
* @param module module that owns the configuration
* @param from resource path to copy defaults from
* @param to destination file path relative to the module data folder
* @return created configuration
*/
ModuleConfiguration create(PlexModule module, String from, String to);
}
}
@@ -2,8 +2,14 @@ package dev.plex.listener;
import org.bukkit.event.Listener;
/**
* Base type for Plex listeners.
*/
public abstract class PlexListener implements Listener
{
/**
* Creates a listener instance.
*/
protected PlexListener()
{
}
@@ -35,23 +35,49 @@ public abstract class PlexModule
private File dataFolder;
private Logger logger;
/**
* Creates a Plex module.
*/
public PlexModule()
{
}
/**
* Returns the Plex API facade.
*
* @return Plex API facade for supported module integrations
*/
public PlexApi api()
{
return api;
}
/**
* Called when the module is loaded.
*/
public void load()
{
}
/**
* Called when the module is enabled.
*/
public void enable()
{
}
/**
* Called when the module is disabled.
*/
public void disable()
{
}
/**
* Registers and tracks a listener owned by this module.
*
* @param listener listener to register
*/
public void registerListener(Listener listener)
{
listeners.add(listener);
@@ -61,6 +87,11 @@ public abstract class PlexModule
}
}
/**
* Unregisters and stops tracking a listener owned by this module.
*
* @param listener listener to unregister
*/
public void unregisterListener(Listener listener)
{
listeners.remove(listener);
@@ -72,6 +103,11 @@ public abstract class PlexModule
HandlerList.unregisterAll(listener);
}
/**
* Registers and tracks a command owned by this module.
*
* @param command command to register
*/
public void registerCommand(PlexCommand command)
{
commands.add(command);
@@ -81,6 +117,11 @@ public abstract class PlexModule
}
}
/**
* Unregisters and stops tracking a command owned by this module.
*
* @param command command to unregister
*/
public void unregisterCommand(PlexCommand command)
{
commands.remove(command);
@@ -90,6 +131,12 @@ public abstract class PlexModule
}
}
/**
* Looks up a tracked command by name or alias.
*
* @param name command name or alias
* @return matching command, or {@code null} when no command matches
*/
@Nullable
public PlexCommand getCommand(String name)
{
@@ -99,6 +146,12 @@ public abstract class PlexModule
.orElse(null);
}
/**
* Adds a default message if the message key is not already configured.
*
* @param message message key
* @param initValue default value to write
*/
public void addDefaultMessage(String message, Object initValue)
{
if (api.configuration().messages().getString(message) == null)
@@ -109,6 +162,13 @@ public abstract class PlexModule
}
}
/**
* Adds a default message and comments if the message key is not already configured.
*
* @param message message key
* @param initValue default value to write
* @param comments comments to write above the message key
*/
public void addDefaultMessage(String message, Object initValue, String... comments)
{
if (api.configuration().messages().getString(message) == null)
@@ -121,6 +181,12 @@ public abstract class PlexModule
}
}
/**
* Opens a resource from this module's class loader.
*
* @param filename resource path
* @return resource stream, or {@code null} when the resource cannot be opened
*/
@Nullable
public InputStream getResource(@NotNull String filename)
{
@@ -142,46 +208,91 @@ public abstract class PlexModule
}
}
/**
* Returns commands currently tracked by this module.
*
* @return commands currently tracked by this module
*/
public List<PlexCommand> getCommands()
{
return commands;
}
/**
* Returns listeners currently tracked by this module.
*
* @return listeners currently tracked by this module
*/
public List<Listener> getListeners()
{
return listeners;
}
/**
* Returns metadata read from this module's module.yml.
*
* @return metadata read from this module's module.yml
*/
public PlexModuleFile getPlexModuleFile()
{
return plexModuleFile;
}
/**
* Returns the module data folder.
*
* @return module data folder
*/
public File getDataFolder()
{
return dataFolder;
}
/**
* Returns the module logger.
*
* @return module logger
*/
public Logger getLogger()
{
return logger;
}
/**
* Sets the Plex API facade for this module.
*
* @param api Plex API facade
*/
public void setApi(PlexApi api)
{
this.api = api;
}
/**
* Sets metadata read from this module's module.yml.
*
* @param plexModuleFile module metadata
*/
public void setPlexModuleFile(PlexModuleFile plexModuleFile)
{
this.plexModuleFile = plexModuleFile;
}
/**
* Sets the module data folder.
*
* @param dataFolder data folder
*/
public void setDataFolder(File dataFolder)
{
this.dataFolder = dataFolder;
}
/**
* Sets the module logger.
*
* @param logger logger
*/
public void setLogger(Logger logger)
{
this.logger = logger;
@@ -15,6 +15,15 @@ public final class PlexModuleFile
private List<String> libraries = List.of();
private List<String> repositories = List.of();
/**
* Creates module metadata.
*
* @param name module name
* @param main main module class
* @param description module description
* @param version module version
* @param apiCompatibility required Plex API compatibility version
*/
public PlexModuleFile(String name, String main, String description, String version, int apiCompatibility)
{
this.name = name;
@@ -24,46 +33,91 @@ public final class PlexModuleFile
this.apiCompatibility = apiCompatibility;
}
/**
* Returns the module name.
*
* @return module name
*/
public String getName()
{
return name;
}
/**
* Returns the main module class.
*
* @return main module class
*/
public String getMain()
{
return main;
}
/**
* Returns the module description.
*
* @return module description
*/
public String getDescription()
{
return description;
}
/**
* Returns the module version.
*
* @return module version
*/
public String getVersion()
{
return version;
}
/**
* Returns the required Plex API compatibility version.
*
* @return required Plex API compatibility version
*/
public int getApiCompatibility()
{
return apiCompatibility;
}
/**
* Returns dependency libraries declared by the module.
*
* @return dependency libraries declared by the module
*/
public List<String> getLibraries()
{
return libraries;
}
/**
* Sets dependency libraries declared by the module.
*
* @param libraries dependency libraries
*/
public void setLibraries(List<String> libraries)
{
this.libraries = List.copyOf(libraries);
}
/**
* Returns Maven repositories declared by the module.
*
* @return Maven repositories declared by the module
*/
public List<String> getRepositories()
{
return repositories;
}
/**
* Sets Maven repositories declared by the module.
*
* @param repositories Maven repositories
*/
public void setRepositories(List<String> repositories)
{
this.repositories = List.copyOf(repositories);
@@ -12,16 +12,32 @@ import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
/**
* Gson adapter that stores {@link ZonedDateTime} values as epoch milliseconds in UTC.
*/
public class ZonedDateTimeAdapter implements JsonSerializer<ZonedDateTime>, JsonDeserializer<ZonedDateTime>
{
private static final ZoneId UTC = ZoneId.of("Etc/UTC");
/**
* Creates a Gson adapter for {@link ZonedDateTime}.
*/
public ZonedDateTimeAdapter()
{
}
/**
* {@inheritDoc}
*/
@Override
public JsonElement serialize(ZonedDateTime src, Type typeOfSrc, JsonSerializationContext context)
{
return new JsonPrimitive(src.toInstant().toEpochMilli());
}
/**
* {@inheritDoc}
*/
@Override
public ZonedDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{