mirror of
https://github.com/plexusorg/Plex.git
synced 2026-06-03 21:16:55 +00:00
New database API
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
plugins {
|
||||
java
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api("com.j256.ormlite:ormlite-core:6.1")
|
||||
api("com.google.code.gson:gson:2.13.2")
|
||||
|
||||
compileOnly("io.papermc.paper:paper-api:26.1.2.build.+")
|
||||
compileOnly("org.apache.logging.log4j:log4j-api:2.26.0")
|
||||
compileOnly("com.google.code.gson:gson:2.13.2")
|
||||
compileOnly("org.jetbrains:annotations:26.1.0")
|
||||
}
|
||||
|
||||
@@ -24,4 +26,4 @@ publishing {
|
||||
from(components["java"])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package dev.plex.api.player;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Typed key-value JSON storage for a player's module data.
|
||||
*/
|
||||
public interface PlayerModuleData
|
||||
{
|
||||
/**
|
||||
* Gets a raw JSON value.
|
||||
*
|
||||
* @param key data key
|
||||
* @return stored JSON value, if present
|
||||
*/
|
||||
Optional<JsonElement> get(String key);
|
||||
|
||||
/**
|
||||
* Gets and maps a JSON value to a Java type.
|
||||
*
|
||||
* @param key data key
|
||||
* @param type target type
|
||||
* @param <T> target type
|
||||
* @return mapped value, if present
|
||||
*/
|
||||
<T> Optional<T> get(String key, Class<T> type);
|
||||
|
||||
/**
|
||||
* Gets a string value.
|
||||
*
|
||||
* @param key data key
|
||||
* @param fallback value returned when the key is absent or incompatible
|
||||
* @return stored string or fallback
|
||||
*/
|
||||
String getString(String key, String fallback);
|
||||
|
||||
/**
|
||||
* Gets a long value.
|
||||
*
|
||||
* @param key data key
|
||||
* @param fallback value returned when the key is absent or incompatible
|
||||
* @return stored long or fallback
|
||||
*/
|
||||
long getLong(String key, long fallback);
|
||||
|
||||
/**
|
||||
* Gets a boolean value.
|
||||
*
|
||||
* @param key data key
|
||||
* @param fallback value returned when the key is absent or incompatible
|
||||
* @return stored boolean or fallback
|
||||
*/
|
||||
boolean getBoolean(String key, boolean fallback);
|
||||
|
||||
/**
|
||||
* Stores a raw JSON value.
|
||||
*
|
||||
* @param key data key
|
||||
* @param value JSON value to store
|
||||
*/
|
||||
void set(String key, JsonElement value);
|
||||
|
||||
/**
|
||||
* Stores a Java value as JSON.
|
||||
*
|
||||
* @param key data key
|
||||
* @param value value to serialize and store
|
||||
*/
|
||||
void set(String key, Object value);
|
||||
|
||||
/**
|
||||
* Removes a stored value.
|
||||
*
|
||||
* @param key data key
|
||||
*/
|
||||
void remove(String key);
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package dev.plex.api.player;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import dev.plex.module.PlexModule;
|
||||
|
||||
/**
|
||||
* Looks up Plex players through read-only API views.
|
||||
@@ -15,7 +16,7 @@ public interface PlayersApi
|
||||
* @param uuid player UUID
|
||||
* @return player view, if known
|
||||
*/
|
||||
Optional<? extends PlexPlayerView> byUuid(UUID uuid);
|
||||
Optional<? extends PlexPlayerView> player(UUID uuid);
|
||||
|
||||
/**
|
||||
* Looks up a player by name.
|
||||
@@ -31,4 +32,13 @@ public interface PlayersApi
|
||||
* @return names of currently online players
|
||||
*/
|
||||
List<String> onlineNames();
|
||||
|
||||
/**
|
||||
* Returns module-scoped data storage for a player.
|
||||
*
|
||||
* @param module module requesting player data
|
||||
* @param playerUuid player UUID
|
||||
* @return module-scoped player data storage
|
||||
*/
|
||||
PlayerModuleData moduleData(PlexModule module, UUID playerUuid);
|
||||
}
|
||||
|
||||
@@ -8,17 +8,18 @@ import java.util.UUID;
|
||||
*
|
||||
* @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 source source that issued the punishment
|
||||
* @param punisherReference source-specific actor reference
|
||||
* @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)
|
||||
public record PunishmentRequest(UUID punished, UUID punisher, PunishmentSource source,
|
||||
String punisherReference, String ip, PunishmentType type,
|
||||
String reason, boolean customTime, boolean active,
|
||||
ZonedDateTime endDate)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package dev.plex.api.punishment;
|
||||
|
||||
/**
|
||||
* Source that issued a punishment.
|
||||
*/
|
||||
public enum PunishmentSource
|
||||
{
|
||||
/**
|
||||
* Punishment issued by an in-game player.
|
||||
*/
|
||||
PLAYER,
|
||||
/**
|
||||
* Punishment issued by the server console.
|
||||
*/
|
||||
CONSOLE,
|
||||
/**
|
||||
* Punishment issued by a web or external integration.
|
||||
*/
|
||||
WEB
|
||||
}
|
||||
@@ -23,11 +23,25 @@ public interface PunishmentView
|
||||
UUID punisher();
|
||||
|
||||
/**
|
||||
* Returns the display name of the actor who issued the punishment.
|
||||
* Returns the source that issued the punishment.
|
||||
*
|
||||
* @return display name of the actor who issued the punishment
|
||||
* @return punishment source
|
||||
*/
|
||||
String punisherName();
|
||||
PunishmentSource source();
|
||||
|
||||
/**
|
||||
* Returns the source-specific punisher reference.
|
||||
*
|
||||
* @return punisher reference, or {@code null} when not applicable
|
||||
*/
|
||||
String punisherReference();
|
||||
|
||||
/**
|
||||
* Returns the resolved display name for the punishment actor.
|
||||
*
|
||||
* @return display name for the punishment actor
|
||||
*/
|
||||
String punisherDisplayName();
|
||||
|
||||
/**
|
||||
* Returns the IP address associated with the punished player.
|
||||
@@ -36,13 +50,6 @@ public interface PunishmentView
|
||||
*/
|
||||
String ip();
|
||||
|
||||
/**
|
||||
* Returns the username of the punished player.
|
||||
*
|
||||
* @return username of the punished player
|
||||
*/
|
||||
String punishedUsername();
|
||||
|
||||
/**
|
||||
* Returns the punishment type.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package dev.plex.api.storage;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Runs database migrations for a module storage namespace.
|
||||
*/
|
||||
public interface ModuleMigrations
|
||||
{
|
||||
/**
|
||||
* Runs migrations from the default module migration resource root.
|
||||
*
|
||||
* @param versions migration versions to apply
|
||||
* @throws SQLException if a migration cannot be applied
|
||||
*/
|
||||
void run(List<String> versions) throws SQLException;
|
||||
|
||||
/**
|
||||
* Runs migrations from a custom module migration resource root.
|
||||
*
|
||||
* @param resourceRoot resource root containing dialect migration folders
|
||||
* @param versions migration versions to apply
|
||||
* @throws SQLException if a migration cannot be applied
|
||||
*/
|
||||
void run(String resourceRoot, List<String> versions) throws SQLException;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package dev.plex.api.storage;
|
||||
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Creates ORMLite DAOs for module-scoped tables.
|
||||
*/
|
||||
public interface ModuleOrm
|
||||
{
|
||||
/**
|
||||
* Creates or returns a cached DAO for a module-local table.
|
||||
*
|
||||
* @param entityClass ORMLite entity class
|
||||
* @param localTableName module-local table name
|
||||
* @param <T> entity type
|
||||
* @param <ID> entity ID type
|
||||
* @return ORMLite DAO using the module-prefixed physical table
|
||||
* @throws SQLException if the DAO cannot be created
|
||||
*/
|
||||
<T, ID> Dao<T, ID> dao(Class<T> entityClass, String localTableName) throws SQLException;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package dev.plex.api.storage;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Module-scoped storage namespace.
|
||||
*/
|
||||
public interface ModuleStorage
|
||||
{
|
||||
/**
|
||||
* Returns the validated module table prefix.
|
||||
*
|
||||
* @return module table prefix
|
||||
*/
|
||||
String prefix();
|
||||
|
||||
/**
|
||||
* Resolves a local table name to the module's physical table name.
|
||||
*
|
||||
* @param localName module-local table name
|
||||
* @return physical table name
|
||||
*/
|
||||
String table(String localName);
|
||||
|
||||
/**
|
||||
* Returns module migration operations.
|
||||
*
|
||||
* @return module migration operations
|
||||
*/
|
||||
ModuleMigrations migrations();
|
||||
|
||||
/**
|
||||
* Returns module ORMLite DAO operations.
|
||||
*
|
||||
* @return module ORMLite DAO operations
|
||||
*/
|
||||
ModuleOrm orm();
|
||||
|
||||
/**
|
||||
* Runs work inside a storage transaction.
|
||||
*
|
||||
* @param callable work to run
|
||||
* @param <T> callback result type
|
||||
* @return callback result
|
||||
* @throws SQLException if the transaction cannot complete
|
||||
*/
|
||||
<T> T transaction(SqlCallable<T> callable) throws SQLException;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package dev.plex.api.storage;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Callback used for SQL work that does not receive a connection directly.
|
||||
*
|
||||
* @param <T> callback result type
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SqlCallable<T>
|
||||
{
|
||||
/**
|
||||
* Runs SQL work.
|
||||
*
|
||||
* @return callback result
|
||||
* @throws SQLException if the SQL work cannot complete
|
||||
*/
|
||||
T call() throws SQLException;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package dev.plex.api.storage;
|
||||
|
||||
/**
|
||||
* SQL dialects supported by Plex storage.
|
||||
*/
|
||||
public enum SqlDialect
|
||||
{
|
||||
/**
|
||||
* SQLite storage.
|
||||
*/
|
||||
SQLITE("sqlite"),
|
||||
/**
|
||||
* MariaDB or MySQL-compatible storage.
|
||||
*/
|
||||
MARIADB("mariadb"),
|
||||
/**
|
||||
* PostgreSQL storage.
|
||||
*/
|
||||
POSTGRES("postgres");
|
||||
|
||||
private final String migrationDirectory;
|
||||
|
||||
SqlDialect(String migrationDirectory)
|
||||
{
|
||||
this.migrationDirectory = migrationDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resource directory name used for dialect-specific migrations.
|
||||
*
|
||||
* @return migration resource directory name
|
||||
*/
|
||||
public String migrationDirectory()
|
||||
{
|
||||
return migrationDirectory;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package dev.plex.api.storage;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import dev.plex.module.PlexModule;
|
||||
|
||||
/**
|
||||
* Provides controlled access to Plex SQL storage.
|
||||
@@ -18,6 +19,21 @@ public interface StorageApi
|
||||
*/
|
||||
<T> T withConnection(SqlFunction<T> function) throws SQLException;
|
||||
|
||||
/**
|
||||
* Returns storage operations scoped to a module namespace.
|
||||
*
|
||||
* @param module module requesting storage
|
||||
* @return module-scoped storage operations
|
||||
*/
|
||||
ModuleStorage forModule(PlexModule module);
|
||||
|
||||
/**
|
||||
* Returns the configured SQL dialect.
|
||||
*
|
||||
* @return configured SQL dialect
|
||||
*/
|
||||
SqlDialect dialect();
|
||||
|
||||
/**
|
||||
* SQL callback used by {@link #withConnection(SqlFunction)}.
|
||||
*
|
||||
|
||||
@@ -45,11 +45,22 @@ public abstract class SimplePlexCommand implements PlexCommand
|
||||
private PlexApi api;
|
||||
private PlexModule module;
|
||||
|
||||
/**
|
||||
* Creates a command using explicit command metadata.
|
||||
*
|
||||
* @param commandSpec command metadata
|
||||
*/
|
||||
protected SimplePlexCommand(CommandSpec commandSpec)
|
||||
{
|
||||
this.commandSpec = commandSpec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a command spec builder for the given command name.
|
||||
*
|
||||
* @param name primary command name
|
||||
* @return command spec builder
|
||||
*/
|
||||
protected static CommandSpec.Builder command(String name)
|
||||
{
|
||||
return CommandSpec.builder(name);
|
||||
@@ -82,6 +93,14 @@ public abstract class SimplePlexCommand implements PlexCommand
|
||||
return command.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Brigadier command tree for this command.
|
||||
*
|
||||
* <p>The default tree accepts optional greedy string arguments and dispatches
|
||||
* them to {@link #execute(CommandSender, Player, String[])}.</p>
|
||||
*
|
||||
* @param command root command literal builder
|
||||
*/
|
||||
protected void configureCommand(LiteralArgumentBuilder<CommandSourceStack> command)
|
||||
{
|
||||
command.executes(context -> dispatchCommand(context, new String[0]));
|
||||
@@ -90,13 +109,36 @@ public abstract class SimplePlexCommand implements PlexCommand
|
||||
.executes(context -> dispatchCommand(context, splitExecutionArgs(StringArgumentType.getString(context, "args")))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes this command.
|
||||
*
|
||||
* @param sender command sender
|
||||
* @param player player sender, or {@code null} when the sender is not a player
|
||||
* @param args command arguments
|
||||
* @return component to send to the sender, or {@code null} to send no response
|
||||
*/
|
||||
protected abstract Component execute(@NotNull CommandSender sender, @Nullable Player player, @NotNull String[] args);
|
||||
|
||||
/**
|
||||
* Returns tab-completion suggestions for this command.
|
||||
*
|
||||
* @param sender command sender
|
||||
* @param alias command alias used by the sender
|
||||
* @param args current command arguments
|
||||
* @return suggested completions
|
||||
* @throws IllegalArgumentException when suggestions cannot be produced for the supplied arguments
|
||||
*/
|
||||
protected @NotNull List<String> suggestions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException
|
||||
{
|
||||
return List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bound Plex API.
|
||||
*
|
||||
* @return bound Plex API
|
||||
* @throws IllegalStateException when the command has not been bound to the API
|
||||
*/
|
||||
protected PlexApi api()
|
||||
{
|
||||
if (api == null)
|
||||
@@ -106,26 +148,56 @@ public abstract class SimplePlexCommand implements PlexCommand
|
||||
return api;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an ampersand-colorized legacy message to an audience.
|
||||
*
|
||||
* @param audience message recipient
|
||||
* @param message legacy message text
|
||||
*/
|
||||
protected void send(Audience audience, String message)
|
||||
{
|
||||
audience.sendMessage(componentFromString(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a component to an audience.
|
||||
*
|
||||
* @param audience message recipient
|
||||
* @param component component to send
|
||||
*/
|
||||
protected void send(Audience audience, Component component)
|
||||
{
|
||||
audience.sendMessage(component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a MiniMessage-formatted message.
|
||||
*
|
||||
* @param miniMessage MiniMessage-formatted message
|
||||
*/
|
||||
protected void broadcast(String miniMessage)
|
||||
{
|
||||
api().messages().broadcast(miniMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a component.
|
||||
*
|
||||
* @param component component to broadcast
|
||||
*/
|
||||
protected void broadcast(Component component)
|
||||
{
|
||||
api().messages().broadcast(component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a sender has a permission node.
|
||||
*
|
||||
* @param sender command sender
|
||||
* @param permission permission node to check
|
||||
* @return {@code true} when the sender can use the permission
|
||||
* @throws CommandFailException when the sender lacks the permission
|
||||
*/
|
||||
protected boolean checkPermission(CommandSender sender, String permission)
|
||||
{
|
||||
if (permission.isEmpty() || isConsole(sender) || sender.hasPermission(permission))
|
||||
@@ -135,31 +207,68 @@ public abstract class SimplePlexCommand implements PlexCommand
|
||||
throw new CommandFailException(messageString("noPermissionNode", permission));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a sender has a permission node without throwing an exception.
|
||||
*
|
||||
* @param sender command sender
|
||||
* @param permission permission node to check
|
||||
* @return {@code true} when the sender can use the permission
|
||||
*/
|
||||
protected boolean silentCheckPermission(CommandSender sender, String permission)
|
||||
{
|
||||
return permission.isEmpty() || isConsole(sender) || sender.hasPermission(permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the standard no-permission message for this command's permission node.
|
||||
*
|
||||
* @return no-permission component
|
||||
*/
|
||||
protected Component permissionMessage()
|
||||
{
|
||||
return permissionMessage(getPermission());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the standard no-permission message for a permission node.
|
||||
*
|
||||
* @param permission permission node
|
||||
* @return no-permission component
|
||||
*/
|
||||
protected Component permissionMessage(String permission)
|
||||
{
|
||||
return messageComponent("noPermissionNode", permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sender's UUID when the sender is a player.
|
||||
*
|
||||
* @param sender command sender
|
||||
* @return player UUID, or {@code null} for non-player senders
|
||||
*/
|
||||
protected @Nullable UUID getUUID(CommandSender sender)
|
||||
{
|
||||
return sender instanceof Player player ? player.getUniqueId() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a sender is not a player.
|
||||
*
|
||||
* @param sender command sender
|
||||
* @return {@code true} when the sender is not a player
|
||||
*/
|
||||
protected boolean isConsole(CommandSender sender)
|
||||
{
|
||||
return !(sender instanceof Player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a configured message as a component.
|
||||
*
|
||||
* @param key message key
|
||||
* @param objects replacement values
|
||||
* @return resolved message component
|
||||
*/
|
||||
protected Component messageComponent(String key, Object... objects)
|
||||
{
|
||||
if (module != null)
|
||||
@@ -169,6 +278,13 @@ public abstract class SimplePlexCommand implements PlexCommand
|
||||
return api().messages().messageComponent(key, objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a configured message as a component using component replacements.
|
||||
*
|
||||
* @param key message key
|
||||
* @param objects replacement components
|
||||
* @return resolved message component
|
||||
*/
|
||||
protected Component messageComponent(String key, Component... objects)
|
||||
{
|
||||
if (module != null)
|
||||
@@ -178,6 +294,13 @@ public abstract class SimplePlexCommand implements PlexCommand
|
||||
return api().messages().messageComponent(key, objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a configured message as plain text.
|
||||
*
|
||||
* @param key message key
|
||||
* @param objects replacement values
|
||||
* @return resolved message text
|
||||
*/
|
||||
protected String messageString(String key, Object... objects)
|
||||
{
|
||||
if (module != null)
|
||||
@@ -187,16 +310,34 @@ public abstract class SimplePlexCommand implements PlexCommand
|
||||
return api().messages().messageString(key, objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this command's formatted usage component.
|
||||
*
|
||||
* @return formatted usage component
|
||||
*/
|
||||
protected Component usage()
|
||||
{
|
||||
return usage(getUsage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats command usage text with the standard usage prefix.
|
||||
*
|
||||
* @param usage usage text
|
||||
* @return formatted usage component
|
||||
*/
|
||||
protected Component usage(String usage)
|
||||
{
|
||||
return messageComponent("correctUsagePrefix").append(componentFromString(usage).color(NamedTextColor.GRAY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an online player by UUID string or name.
|
||||
*
|
||||
* @param name UUID string or player name
|
||||
* @return matching online player
|
||||
* @throws PlayerNotFoundException when no matching online player exists
|
||||
*/
|
||||
protected Player getNonNullPlayer(String name)
|
||||
{
|
||||
try
|
||||
@@ -220,21 +361,44 @@ public abstract class SimplePlexCommand implements PlexCommand
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of currently online players.
|
||||
*
|
||||
* @return online player names
|
||||
*/
|
||||
protected List<String> onlinePlayerNames()
|
||||
{
|
||||
return api().players().onlineNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts ampersand-colorized legacy text to a gray-default component.
|
||||
*
|
||||
* @param value legacy text
|
||||
* @return deserialized component
|
||||
*/
|
||||
protected Component componentFromString(String value)
|
||||
{
|
||||
return LegacyComponentSerializer.legacyAmpersand().deserialize(value).colorIfAbsent(NamedTextColor.GRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts ampersand-colorized legacy text to a component without adding a default color.
|
||||
*
|
||||
* @param value legacy text
|
||||
* @return deserialized component
|
||||
*/
|
||||
protected Component noColorComponentFromString(String value)
|
||||
{
|
||||
return LegacyComponentSerializer.legacyAmpersand().deserialize(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts MiniMessage-formatted text to a component.
|
||||
*
|
||||
* @param value MiniMessage-formatted text
|
||||
* @return deserialized component
|
||||
*/
|
||||
protected Component mmString(String value)
|
||||
{
|
||||
return api().messages().miniMessage(value);
|
||||
|
||||
Reference in New Issue
Block a user