mirror of
https://github.com/Xiao-MoMi/Custom-Nameplates.git
synced 2025-12-19 15:09:23 +00:00
merge modules
This commit is contained in:
@@ -25,7 +25,7 @@ Get the artifact under /target folder
|
||||
## How to Contribute
|
||||
|
||||
#### Translations
|
||||
Clone this project and create a new language file in the /common/src/main/resources/translations directory. \
|
||||
Clone this project and create a new language file in the /backend/src/main/resources/translations directory. \
|
||||
Once your changes are ready, open a pull request for review. We appreciate your works!
|
||||
|
||||
## Support the Developer
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
plugins {
|
||||
id("io.github.goooler.shadow") version "8.1.8"
|
||||
id("maven-publish")
|
||||
}
|
||||
|
||||
@@ -10,21 +9,32 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":common"))
|
||||
// Adventure
|
||||
implementation("net.kyori:adventure-api:${rootProject.properties["adventure_bundle_version"]}")
|
||||
compileOnly("net.kyori:adventure-text-minimessage:${rootProject.properties["adventure_bundle_version"]}")
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:${rootProject.properties["adventure_bundle_version"]}")
|
||||
compileOnly("net.kyori:adventure-text-minimessage:${rootProject.properties["adventure_bundle_version"]}")
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:${rootProject.properties["adventure_bundle_version"]}")
|
||||
// YAML
|
||||
implementation(files("libs/boosted-yaml-${rootProject.properties["boosted_yaml_version"]}.jar"))
|
||||
// Cache
|
||||
compileOnly("com.github.ben-manes.caffeine:caffeine:${rootProject.properties["caffeine_version"]}")
|
||||
// Netty
|
||||
compileOnly("io.netty:netty-all:4.1.113.Final")
|
||||
compileOnly("io.netty:netty-all:4.1.117.Final")
|
||||
// GSON
|
||||
compileOnly("com.google.code.gson:gson:${rootProject.properties["gson_version"]}")
|
||||
// Fast util
|
||||
compileOnly("it.unimi.dsi:fastutil:${rootProject.properties["fastutil_version"]}")
|
||||
// Command
|
||||
compileOnly("org.incendo:cloud-core:${rootProject.properties["cloud_core_version"]}")
|
||||
compileOnly("org.incendo:cloud-minecraft-extras:${rootProject.properties["cloud_minecraft_extras_version"]}")
|
||||
// Logger
|
||||
compileOnly("org.slf4j:slf4j-api:${rootProject.properties["slf4j_version"]}")
|
||||
compileOnly("org.apache.logging.log4j:log4j-core:${rootProject.properties["log4j_version"]}")
|
||||
// Expression
|
||||
compileOnly("net.objecthunter:exp4j:${rootProject.properties["exp4j_version"]}")
|
||||
// code generator
|
||||
compileOnly("net.bytebuddy:byte-buddy:${rootProject.properties["byte_buddy_version"]}")
|
||||
}
|
||||
|
||||
java {
|
||||
@@ -34,7 +44,6 @@ java {
|
||||
languageVersion = JavaLanguageVersion.of(17)
|
||||
}
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
@@ -45,7 +54,7 @@ tasks.withType<JavaCompile> {
|
||||
|
||||
tasks {
|
||||
shadowJar {
|
||||
// archiveClassifier.set("")
|
||||
archiveClassifier.set("")
|
||||
archiveFileName = "custom-nameplates-${rootProject.properties["project_version"]}.jar"
|
||||
relocate ("net.kyori", "net.momirealms.customnameplates.libraries")
|
||||
relocate("dev.dejvokep", "net.momirealms.customnameplates.libraries")
|
||||
@@ -73,10 +82,18 @@ publishing {
|
||||
groupId = "net.momirealms"
|
||||
artifactId = "custom-nameplates"
|
||||
version = rootProject.properties["project_version"].toString()
|
||||
from(components["java"])
|
||||
artifact(tasks["sourcesJar"])
|
||||
from(components["shadow"])
|
||||
pom {
|
||||
name = "CustomNameplates API"
|
||||
url = "https://momirealms.net"
|
||||
url = "https://github.com/Xiao-MoMi/Custom-Nameplates"
|
||||
licenses {
|
||||
license {
|
||||
name = "GNU General Public License v3.0"
|
||||
url = "https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
distribution = "repo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.command;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.momirealms.customnameplates.common.sender.SenderFactory;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
|
||||
/**
|
||||
* Abstract base class for command feature implementations within the Custom Nameplates command system.
|
||||
* This class provides utility methods for command registration, feedback handling, and configuration.
|
||||
*
|
||||
* @param <C> The type of the sender (e.g., a player or console sender) for the command.
|
||||
*/
|
||||
public abstract class AbstractCommandFeature<C> implements CommandFeature<C> {
|
||||
/**
|
||||
* The command manager
|
||||
*/
|
||||
protected final CustomNameplatesCommandManager<C> commandManager;
|
||||
/**
|
||||
* The command config
|
||||
*/
|
||||
protected CommandConfig commandConfig;
|
||||
|
||||
/**
|
||||
* Constructs an AbstractCommandFeature instance with the given command manager.
|
||||
*
|
||||
* @param commandManager The command manager to manage the commands associated with this feature.
|
||||
*/
|
||||
public AbstractCommandFeature(CustomNameplatesCommandManager<C> commandManager) {
|
||||
this.commandManager = commandManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method to retrieve the sender factory for the command.
|
||||
* Implementations must provide the logic for creating senders of type C.
|
||||
*
|
||||
* @return The sender factory for the command.
|
||||
*/
|
||||
protected abstract SenderFactory<?, C> getSenderFactory();
|
||||
|
||||
/**
|
||||
* Abstract method to assemble the command builder with the given manager.
|
||||
* Implementations must define how to build the command.
|
||||
*
|
||||
* @param manager The command manager responsible for managing the command.
|
||||
* @param builder The builder used to construct the command.
|
||||
* @return A command builder ready to be built.
|
||||
*/
|
||||
public abstract Command.Builder<? extends C> assembleCommand(CommandManager<C> manager, Command.Builder<C> builder);
|
||||
|
||||
/**
|
||||
* Registers the command with the provided command manager.
|
||||
* This method builds the command and registers it with the command manager.
|
||||
*
|
||||
* @param manager The command manager to register the command with.
|
||||
* @param builder The builder used to create the command.
|
||||
* @return The registered command.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Command<C> registerCommand(CommandManager<C> manager, Command.Builder<C> builder) {
|
||||
Command<C> command = (Command<C>) assembleCommand(manager, builder).build();
|
||||
manager.command(command);
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers any related functions or hooks. This method is a no-op by default
|
||||
* and can be overridden in subclasses to register additional functionality.
|
||||
*/
|
||||
@Override
|
||||
public void registerRelatedFunctions() {
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters any related functions or hooks. This method is a no-op by default
|
||||
* and can be overridden in subclasses to unregister additional functionality.
|
||||
*/
|
||||
@Override
|
||||
public void unregisterRelatedFunctions() {
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles feedback for the command execution, sending a translation message to the sender.
|
||||
* The feedback is suppressed if the "silent" flag is present in the command context.
|
||||
*
|
||||
* @param context The command context containing information about the sender and flags.
|
||||
* @param key The key for the translation component to be used as feedback.
|
||||
* @param args The arguments to be passed to the translation.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void handleFeedback(CommandContext<?> context, TranslatableComponent.Builder key, Component... args) {
|
||||
if (context.flags().hasFlag("silent")) {
|
||||
return;
|
||||
}
|
||||
commandManager.handleCommandFeedback((C) context.sender(), key, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles feedback for the command execution, sending a translation message to the sender.
|
||||
*
|
||||
* @param sender The sender to receive the feedback.
|
||||
* @param key The key for the translation component to be used as feedback.
|
||||
* @param args The arguments to be passed to the translation.
|
||||
*/
|
||||
@Override
|
||||
public void handleFeedback(C sender, TranslatableComponent.Builder key, Component... args) {
|
||||
commandManager.handleCommandFeedback(sender, key, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the command manager associated with this feature.
|
||||
*
|
||||
* @return The command manager.
|
||||
*/
|
||||
@Override
|
||||
public CustomNameplatesCommandManager<C> getCustomNameplatesCommandManager() {
|
||||
return commandManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the configuration associated with the command.
|
||||
*
|
||||
* @return The command configuration.
|
||||
*/
|
||||
@Override
|
||||
public CommandConfig getCommandConfig() {
|
||||
return commandConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configuration for the command.
|
||||
*
|
||||
* @param commandConfig The configuration to set for the command.
|
||||
*/
|
||||
public void setCommandConfig(CommandConfig commandConfig) {
|
||||
this.commandConfig = commandConfig;
|
||||
}
|
||||
}
|
||||
@@ -49,17 +49,39 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* An abstract implementation of the {@link CustomNameplatesCommandManager} that handles the management and registration of command features,
|
||||
* exception handling, and feedback handling within the Custom Nameplates plugin.
|
||||
*
|
||||
* @param <C> The type of the sender (e.g., player, console) for the commands.
|
||||
*/
|
||||
public abstract class AbstractCommandManager<C> implements CustomNameplatesCommandManager<C> {
|
||||
|
||||
/**
|
||||
* Registered commands
|
||||
*/
|
||||
protected final HashSet<CommandComponent<C>> registeredRootCommandComponents = new HashSet<>();
|
||||
/**
|
||||
* Registered features
|
||||
*/
|
||||
protected final HashSet<CommandFeature<C>> registeredFeatures = new HashSet<>();
|
||||
/**
|
||||
* The command manager
|
||||
*/
|
||||
protected final CommandManager<C> commandManager;
|
||||
/**
|
||||
* The NameplatesPlugin
|
||||
*/
|
||||
protected final NameplatesPlugin plugin;
|
||||
private final CustomNameplatesCaptionFormatter<C> captionFormatter = new CustomNameplatesCaptionFormatter<C>();
|
||||
private final MinecraftExceptionHandler.Decorator<C> decorator = (formatter, ctx, msg) -> msg;
|
||||
|
||||
private TriConsumer<C, String, Component> feedbackConsumer;
|
||||
|
||||
/**
|
||||
* Constructs an AbstractCommandManager instance with the provided plugin and command manager.
|
||||
*
|
||||
* @param plugin The plugin instance managing this command manager.
|
||||
* @param commandManager The command manager instance that handles the command registration.
|
||||
*/
|
||||
public AbstractCommandManager(NameplatesPlugin plugin, CommandManager<C> commandManager) {
|
||||
this.commandManager = commandManager;
|
||||
this.plugin = plugin;
|
||||
@@ -86,6 +108,12 @@ public abstract class AbstractCommandManager<C> implements CustomNameplatesComma
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a sender base on platform
|
||||
*
|
||||
* @param c sender
|
||||
* @return the wrapped sender
|
||||
*/
|
||||
protected abstract Sender wrapSender(C c);
|
||||
|
||||
private void inject() {
|
||||
@@ -108,7 +136,7 @@ public abstract class AbstractCommandManager<C> implements CustomNameplatesComma
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfig<C> getCommandConfig(YamlDocument document, String featureID) {
|
||||
public CommandConfig getCommandConfig(YamlDocument document, String featureID) {
|
||||
Section section = document.getSection(featureID);
|
||||
if (section == null) return null;
|
||||
return new CommandConfig.Builder<C>()
|
||||
@@ -119,7 +147,7 @@ public abstract class AbstractCommandManager<C> implements CustomNameplatesComma
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Command.Builder<C>> buildCommandBuilders(CommandConfig<C> config) {
|
||||
public Collection<Command.Builder<C>> buildCommandBuilders(CommandConfig config) {
|
||||
ArrayList<Command.Builder<C>> list = new ArrayList<>();
|
||||
for (String usage : config.getUsages()) {
|
||||
if (!usage.startsWith("/")) continue;
|
||||
@@ -135,7 +163,7 @@ public abstract class AbstractCommandManager<C> implements CustomNameplatesComma
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerFeature(CommandFeature<C> feature, CommandConfig<C> config) {
|
||||
public void registerFeature(CommandFeature<C> feature, CommandConfig config) {
|
||||
if (!config.isEnable()) throw new RuntimeException("Registering a disabled command feature is not allowed");
|
||||
for (Command.Builder<C> builder : buildCommandBuilders(config)) {
|
||||
Command<C> command = feature.registerCommand(commandManager, builder);
|
||||
@@ -155,7 +183,7 @@ public abstract class AbstractCommandManager<C> implements CustomNameplatesComma
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.getFeatures().values().forEach(feature -> {
|
||||
CommandConfig<C> config = getCommandConfig(document, feature.getFeatureID());
|
||||
CommandConfig config = getCommandConfig(document, feature.getFeatureID());
|
||||
if (config.isEnable()) {
|
||||
registerFeature(feature, config);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.command;
|
||||
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
|
||||
/**
|
||||
* A builder interface for constructing commands with configurable parameters.
|
||||
* This interface allows setting permissions, command nodes (subcommands), and
|
||||
* building the final {@link Command.Builder} object.
|
||||
*/
|
||||
public interface CommandBuilder<C> {
|
||||
|
||||
/**
|
||||
* Sets the permission required to execute the command.
|
||||
*
|
||||
* @param permission the permission string required for executing the command.
|
||||
* @return the current {@link CommandBuilder} instance for method chaining.
|
||||
*/
|
||||
CommandBuilder<C> setPermission(String permission);
|
||||
|
||||
/**
|
||||
* Sets the subcommands (nodes) for the command.
|
||||
* This allows defining a hierarchy of commands.
|
||||
*
|
||||
* @param subNodes the subcommands or nodes to add to the command.
|
||||
* @return the current {@link CommandBuilder} instance for method chaining.
|
||||
*/
|
||||
CommandBuilder<C> setCommandNode(String... subNodes);
|
||||
|
||||
/**
|
||||
* Retrieves the fully constructed {@link Command.Builder} instance.
|
||||
* This method returns the builder object that can be used to further configure
|
||||
* and register the command.
|
||||
*
|
||||
* @return the built {@link Command.Builder} instance.
|
||||
*/
|
||||
Command.Builder<C> getBuiltCommandBuilder();
|
||||
|
||||
/**
|
||||
* Basic implementation of the {@link CommandBuilder} interface.
|
||||
* This class provides a default implementation for constructing a command
|
||||
* with the given root node, permission, and subcommand nodes.
|
||||
*
|
||||
* @param <C> The type of context or object associated with the command.
|
||||
*/
|
||||
class BasicCommandBuilder<C> implements CommandBuilder<C> {
|
||||
|
||||
/**
|
||||
* The actual command builder used to construct the command.
|
||||
*/
|
||||
private Command.Builder<C> commandBuilder;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link BasicCommandBuilder} for building a command.
|
||||
*
|
||||
* @param commandManager the {@link CommandManager} instance used for creating the command builder.
|
||||
* @param rootNode the root node for the command.
|
||||
*/
|
||||
public BasicCommandBuilder(CommandManager<C> commandManager, String rootNode) {
|
||||
this.commandBuilder = commandManager.commandBuilder(rootNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the permission for the command.
|
||||
*
|
||||
* @param permission the permission required for executing the command.
|
||||
* @return the current {@link CommandBuilder} instance for method chaining.
|
||||
*/
|
||||
@Override
|
||||
public CommandBuilder<C> setPermission(String permission) {
|
||||
this.commandBuilder = this.commandBuilder.permission(permission);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subcommands (nodes) for the command.
|
||||
*
|
||||
* @param subNodes the subcommands to add to the command.
|
||||
* @return the current {@link CommandBuilder} instance for method chaining.
|
||||
*/
|
||||
@Override
|
||||
public CommandBuilder<C> setCommandNode(String... subNodes) {
|
||||
for (String sub : subNodes) {
|
||||
this.commandBuilder = this.commandBuilder.literal(sub);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the built {@link Command.Builder} instance.
|
||||
*
|
||||
* @return the built {@link Command.Builder} instance.
|
||||
*/
|
||||
@Override
|
||||
public Command.Builder<C> getBuiltCommandBuilder() {
|
||||
return commandBuilder;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A configuration class for setting up command-related options such as enabling/disabling,
|
||||
* command usages, and required permissions.
|
||||
* <p>
|
||||
* This class provides a builder pattern implementation to easily create and configure
|
||||
* a {@link CommandConfig} object with a fluent API.
|
||||
*/
|
||||
public class CommandConfig {
|
||||
|
||||
/**
|
||||
* Flag indicating whether the command is enabled.
|
||||
*/
|
||||
private boolean enable = false;
|
||||
|
||||
/**
|
||||
* List of command usage examples or syntax hints.
|
||||
*/
|
||||
private List<String> usages = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Permission required to execute the command.
|
||||
*/
|
||||
private String permission = null;
|
||||
|
||||
/**
|
||||
* Private constructor to prevent direct instantiation.
|
||||
* Use the {@link Builder} class to construct an instance.
|
||||
*/
|
||||
private CommandConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link CommandConfig} with the specified values.
|
||||
*
|
||||
* @param enable whether the command is enabled.
|
||||
* @param usages the list of command usages.
|
||||
* @param permission the permission required to execute the command.
|
||||
*/
|
||||
public CommandConfig(boolean enable, List<String> usages, String permission) {
|
||||
this.enable = enable;
|
||||
this.usages = usages;
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the command is enabled.
|
||||
*
|
||||
* @return true if the command is enabled, false otherwise.
|
||||
*/
|
||||
public boolean isEnable() {
|
||||
return enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of command usages or syntax examples.
|
||||
*
|
||||
* @return the list of command usages.
|
||||
*/
|
||||
public List<String> getUsages() {
|
||||
return usages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the permission required to execute the command.
|
||||
*
|
||||
* @return the permission string.
|
||||
*/
|
||||
public String getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for constructing a {@link CommandConfig} object with customizable options.
|
||||
* This allows setting values for enabling the command, defining usages, and setting permissions.
|
||||
*
|
||||
* @param <C> the context type associated with the command.
|
||||
*/
|
||||
public static class Builder<C> {
|
||||
|
||||
/**
|
||||
* The {@link CommandConfig} object being built.
|
||||
*/
|
||||
private final CommandConfig config;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link Builder} for {@link CommandConfig}.
|
||||
* Initializes the config object to default values.
|
||||
*/
|
||||
public Builder() {
|
||||
this.config = new CommandConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of command usages (examples or syntax hints).
|
||||
*
|
||||
* @param usages the list of command usages.
|
||||
* @return the current {@link Builder} instance for method chaining.
|
||||
*/
|
||||
public Builder<C> usages(List<String> usages) {
|
||||
config.usages = usages;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the permission required to execute the command.
|
||||
*
|
||||
* @param permission the permission string.
|
||||
* @return the current {@link Builder} instance for method chaining.
|
||||
*/
|
||||
public Builder<C> permission(String permission) {
|
||||
config.permission = permission;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the command is enabled.
|
||||
*
|
||||
* @param enable true to enable the command, false to disable it.
|
||||
* @return the current {@link Builder} instance for method chaining.
|
||||
*/
|
||||
public Builder<C> enable(boolean enable) {
|
||||
config.enable = enable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns the constructed {@link CommandConfig} object.
|
||||
*
|
||||
* @return the {@link CommandConfig} object.
|
||||
*/
|
||||
public CommandConfig build() {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.command;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
|
||||
/**
|
||||
* Represents the contract for a feature that provides a command in the Custom Nameplates system.
|
||||
* This interface defines methods for registering commands, handling feedback, and managing related functionality.
|
||||
*
|
||||
* @param <C> The type of the sender (e.g., player, console) for the command.
|
||||
*/
|
||||
public interface CommandFeature<C> {
|
||||
|
||||
/**
|
||||
* Registers the command with the provided command manager and builder.
|
||||
*
|
||||
* @param cloudCommandManager The command manager responsible for managing commands.
|
||||
* @param builder The command builder used to create the command.
|
||||
* @return The registered command.
|
||||
*/
|
||||
Command<C> registerCommand(CommandManager<C> cloudCommandManager, Command.Builder<C> builder);
|
||||
|
||||
/**
|
||||
* Retrieves a unique identifier for this feature.
|
||||
* The feature ID is used to identify the feature within the system.
|
||||
*
|
||||
* @return A unique identifier for this command feature.
|
||||
*/
|
||||
String getFeatureID();
|
||||
|
||||
/**
|
||||
* Registers any related functions or hooks that this feature may require.
|
||||
* This method may be used to register additional functionality necessary for the feature.
|
||||
*/
|
||||
void registerRelatedFunctions();
|
||||
|
||||
/**
|
||||
* Unregisters any related functions or hooks that were previously registered.
|
||||
* This method is used for cleaning up after the feature when it's no longer needed.
|
||||
*/
|
||||
void unregisterRelatedFunctions();
|
||||
|
||||
/**
|
||||
* Handles feedback for the command execution, sending a translation message to the sender.
|
||||
* The feedback may be affected by the flags in the command context (e.g., silent mode).
|
||||
*
|
||||
* @param context The command context containing information about the sender and flags.
|
||||
* @param key The key for the translation component to be used as feedback.
|
||||
* @param args The arguments to be passed to the translation.
|
||||
*/
|
||||
void handleFeedback(CommandContext<?> context, TranslatableComponent.Builder key, Component... args);
|
||||
|
||||
/**
|
||||
* Handles feedback for the command execution, sending a translation message to the sender.
|
||||
*
|
||||
* @param sender The sender to receive the feedback.
|
||||
* @param key The key for the translation component to be used as feedback.
|
||||
* @param args The arguments to be passed to the translation.
|
||||
*/
|
||||
void handleFeedback(C sender, TranslatableComponent.Builder key, Component... args);
|
||||
|
||||
/**
|
||||
* Retrieves the command manager associated with this feature.
|
||||
*
|
||||
* @return The command manager.
|
||||
*/
|
||||
CustomNameplatesCommandManager<C> getCustomNameplatesCommandManager();
|
||||
|
||||
/**
|
||||
* Retrieves the configuration associated with the command.
|
||||
*
|
||||
* @return The command configuration.
|
||||
*/
|
||||
CommandConfig getCommandConfig();
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.command;
|
||||
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.util.Index;
|
||||
import net.momirealms.customnameplates.common.util.TriConsumer;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Interface for managing commands within the Custom Nameplates plugin. This interface defines methods for
|
||||
* registering features, handling feedback, and interacting with the command manager and configurations.
|
||||
*
|
||||
* @param <C> The type of the sender (e.g., player, console) for the commands.
|
||||
*/
|
||||
public interface CustomNameplatesCommandManager<C> {
|
||||
|
||||
/**
|
||||
* The default configuration file name for commands
|
||||
*/
|
||||
String commandsFile = "commands.yml";
|
||||
|
||||
/**
|
||||
* Unregisters all previously registered command features.
|
||||
*/
|
||||
void unregisterFeatures();
|
||||
|
||||
/**
|
||||
* Registers a command feature with the provided configuration.
|
||||
*
|
||||
* @param feature The command feature to register.
|
||||
* @param config The configuration for the feature.
|
||||
*/
|
||||
void registerFeature(CommandFeature<C> feature, CommandConfig config);
|
||||
|
||||
/**
|
||||
* Registers all default features based on the plugin configuration.
|
||||
*/
|
||||
void registerDefaultFeatures();
|
||||
|
||||
/**
|
||||
* Retrieves all registered command features in the form of an index.
|
||||
*
|
||||
* @return The index of registered command features.
|
||||
*/
|
||||
Index<String, CommandFeature<C>> getFeatures();
|
||||
|
||||
/**
|
||||
* Sets a custom feedback consumer that handles the feedback sent to the command sender.
|
||||
*
|
||||
* @param feedbackConsumer The custom feedback consumer.
|
||||
*/
|
||||
void setFeedbackConsumer(@NotNull TriConsumer<C, String, Component> feedbackConsumer);
|
||||
|
||||
/**
|
||||
* Provides the default feedback consumer for sending feedback messages.
|
||||
*
|
||||
* @return The default feedback consumer.
|
||||
*/
|
||||
TriConsumer<C, String, Component> defaultFeedbackConsumer();
|
||||
|
||||
/**
|
||||
* Retrieves the command configuration from a YAML document and a given feature ID.
|
||||
*
|
||||
* @param document The YAML document containing the configuration.
|
||||
* @param featureID The ID of the feature to retrieve configuration for.
|
||||
* @return The command configuration for the specified feature, or null if not found.
|
||||
*/
|
||||
CommandConfig getCommandConfig(YamlDocument document, String featureID);
|
||||
|
||||
/**
|
||||
* Builds a collection of command builders based on the given configuration.
|
||||
*
|
||||
* @param config The command configuration.
|
||||
* @return A collection of command builders.
|
||||
*/
|
||||
Collection<Command.Builder<C>> buildCommandBuilders(CommandConfig config);
|
||||
|
||||
/**
|
||||
* Retrieves the command manager associated with this command manager.
|
||||
*
|
||||
* @return The command manager.
|
||||
*/
|
||||
CommandManager<C> getCommandManager();
|
||||
|
||||
/**
|
||||
* Sends feedback to the sender based on the provided key and arguments.
|
||||
*
|
||||
* @param sender The sender of the command.
|
||||
* @param key The key used to retrieve the feedback message.
|
||||
* @param args The arguments to be included in the feedback message.
|
||||
*/
|
||||
void handleCommandFeedback(C sender, TranslatableComponent.Builder key, Component... args);
|
||||
|
||||
/**
|
||||
* Sends feedback to the sender based on the provided node and component.
|
||||
*
|
||||
* @param sender The sender of the command.
|
||||
* @param node The feedback node.
|
||||
* @param component The component containing the feedback message.
|
||||
*/
|
||||
void handleCommandFeedback(C sender, String node, Component component);
|
||||
}
|
||||
@@ -1,26 +1,18 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.dependency;
|
||||
@@ -356,10 +348,27 @@ public enum Dependency {
|
||||
|
||||
private static final String MAVEN_FORMAT = "%s/%s/%s/%s-%s.jar";
|
||||
|
||||
/**
|
||||
* Constructs a Dependency with the given group ID, artifact ID, repository, and custom artifact ID.
|
||||
*
|
||||
* @param groupId the group ID of the dependency
|
||||
* @param artifactId the artifact ID of the dependency
|
||||
* @param repo the repository for the dependency
|
||||
* @param customArtifactID the custom artifact ID for the dependency
|
||||
*/
|
||||
Dependency(String groupId, String artifactId, String repo, String customArtifactID) {
|
||||
this(groupId, artifactId, repo, customArtifactID, new Relocation[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Dependency with the given group ID, artifact ID, repository, custom artifact ID, and relocations.
|
||||
*
|
||||
* @param groupId the group ID of the dependency
|
||||
* @param artifactId the artifact ID of the dependency
|
||||
* @param repo the repository for the dependency
|
||||
* @param customArtifactID the custom artifact ID for the dependency
|
||||
* @param relocations any relocations associated with the dependency
|
||||
*/
|
||||
Dependency(String groupId, String artifactId, String repo, String customArtifactID, Relocation... relocations) {
|
||||
this.artifactId = artifactId;
|
||||
this.artifactIdSuffix = "";
|
||||
@@ -369,6 +378,16 @@ public enum Dependency {
|
||||
this.customArtifactID = customArtifactID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Dependency with the given group ID, artifact ID, repository, custom artifact ID, and relocations.
|
||||
*
|
||||
* @param groupId the group ID of the dependency
|
||||
* @param artifactId the artifact ID of the dependency
|
||||
* @param repo the repository for the dependency
|
||||
* @param customArtifactID the custom artifact ID for the dependency
|
||||
* @param artifactIdSuffix the custom artifact suffix
|
||||
* @param relocations any relocations associated with the dependency
|
||||
*/
|
||||
Dependency(String groupId, String artifactId, String repo, String customArtifactID, String artifactIdSuffix, Relocation... relocations) {
|
||||
this.artifactId = artifactId;
|
||||
this.artifactIdSuffix = artifactIdSuffix;
|
||||
@@ -378,10 +397,20 @@ public enum Dependency {
|
||||
this.customArtifactID = customArtifactID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the artifact suffix
|
||||
*
|
||||
* @param artifactIdSuffix the artifact suffix
|
||||
*/
|
||||
public void setArtifactIdSuffix(String artifactIdSuffix) {
|
||||
this.artifactIdSuffix = artifactIdSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the dependency based on the custom artifact ID.
|
||||
*
|
||||
* @return the version of the dependency
|
||||
*/
|
||||
public String getVersion() {
|
||||
return CustomNameplatesProperties.getValue(customArtifactID);
|
||||
}
|
||||
@@ -390,6 +419,12 @@ public enum Dependency {
|
||||
return s.replace("{}", ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filename for the dependency's JAR file, optionally with a classifier.
|
||||
*
|
||||
* @param classifier the classifier for the JAR (e.g., "sources" or "javadoc")
|
||||
* @return the filename for the JAR
|
||||
*/
|
||||
public String getFileName(String classifier) {
|
||||
String name = customArtifactID.toLowerCase(Locale.ROOT).replace('_', '-');
|
||||
String extra = classifier == null || classifier.isEmpty()
|
||||
@@ -398,6 +433,11 @@ public enum Dependency {
|
||||
return name + "-" + this.getVersion() + extra + ".jar";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Maven repository path for the dependency.
|
||||
*
|
||||
* @return the Maven repository path
|
||||
*/
|
||||
String getMavenRepoPath() {
|
||||
return String.format(MAVEN_FORMAT,
|
||||
rewriteEscaping(groupId).replace(".", "/"),
|
||||
@@ -408,6 +448,11 @@ public enum Dependency {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of relocations for the dependency.
|
||||
*
|
||||
* @return a list of {@link Relocation} objects
|
||||
*/
|
||||
public List<Relocation> getRelocations() {
|
||||
return this.relocations;
|
||||
}
|
||||
@@ -426,6 +471,11 @@ public enum Dependency {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the repo
|
||||
*
|
||||
* @return the repo
|
||||
*/
|
||||
@Nullable
|
||||
public String getRepo() {
|
||||
return repo;
|
||||
@@ -30,18 +30,20 @@ package net.momirealms.customnameplates.common.dependency;
|
||||
*/
|
||||
public class DependencyDownloadException extends Exception {
|
||||
|
||||
public DependencyDownloadException() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new DependencyDownloadException with the specified detail message.
|
||||
*
|
||||
* @param message the detail message, which provides additional information about the error
|
||||
*/
|
||||
public DependencyDownloadException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DependencyDownloadException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new DependencyDownloadException with the specified cause.
|
||||
*
|
||||
* @param cause the cause of the exception, which can be retrieved later with {@link Throwable#getCause()}
|
||||
*/
|
||||
public DependencyDownloadException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
@@ -61,6 +61,11 @@ public class DependencyManagerImpl implements DependencyManager {
|
||||
private final Executor loadingExecutor;
|
||||
private final NameplatesPlugin plugin;
|
||||
|
||||
/**
|
||||
* Constructs a DependencyManagerImpl instance
|
||||
*
|
||||
* @param plugin plugin
|
||||
*/
|
||||
public DependencyManagerImpl(NameplatesPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.registry = new DependencyRegistry();
|
||||
@@ -32,6 +32,12 @@ import com.google.gson.JsonElement;
|
||||
*/
|
||||
public class DependencyRegistry {
|
||||
|
||||
/**
|
||||
* Check if the dependency should be automatically loaded
|
||||
*
|
||||
* @param dependency dependency
|
||||
* @return should be automatically loaded or not
|
||||
*/
|
||||
public boolean shouldAutoLoad(Dependency dependency) {
|
||||
return switch (dependency) {
|
||||
// all used within 'isolated' classloaders, and are therefore not
|
||||
@@ -41,6 +47,11 @@ public class DependencyRegistry {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if gson is relocated
|
||||
*
|
||||
* @return relocated or not
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public static boolean isGsonRelocated() {
|
||||
return JsonElement.class.getName().startsWith("net.momirealms");
|
||||
@@ -58,5 +69,4 @@ public class DependencyRegistry {
|
||||
private static boolean slf4jPresent() {
|
||||
return classExists("org.slf4j.Logger") && classExists("org.slf4j.LoggerFactory");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -66,6 +66,11 @@ public enum DependencyRepository {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the url of this repo
|
||||
*
|
||||
* @return the url
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
@@ -17,16 +17,23 @@
|
||||
|
||||
package net.momirealms.customnameplates.common.event;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
/**
|
||||
* Interface representing an event or task that can be cancelled.
|
||||
* This interface defines methods to check and set the cancellation state of the event or task.
|
||||
*/
|
||||
public interface Cancellable {
|
||||
|
||||
public interface CommandFeedbackEvent<C> extends NameplatesEvent, Cancellable {
|
||||
/**
|
||||
* Gets the current cancelled state of the event or task.
|
||||
*
|
||||
* @return true if the event or task has been cancelled, false otherwise.
|
||||
*/
|
||||
boolean cancelled();
|
||||
|
||||
@Param(0)
|
||||
C sender();
|
||||
|
||||
@Param(1)
|
||||
String key();
|
||||
|
||||
@Param(2)
|
||||
Component message();
|
||||
/**
|
||||
* Sets the cancelled state of the event or task.
|
||||
*
|
||||
* @param cancelled a boolean indicating whether the event is cancelled
|
||||
*/
|
||||
void cancelled(final boolean cancelled);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.event;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
/**
|
||||
* An event that represents feedback generated by a command execution.
|
||||
* This event contains the sender of the command, the associated key, and the feedback message.
|
||||
*/
|
||||
public interface CommandFeedbackEvent<C> extends NameplatesEvent, Cancellable {
|
||||
|
||||
/**
|
||||
* Gets the sender of the command that triggered this event.
|
||||
*
|
||||
* @return the sender (e.g., player or entity) of the command.
|
||||
*/
|
||||
@Param(0)
|
||||
C sender();
|
||||
|
||||
/**
|
||||
* Gets the key associated with the feedback message.
|
||||
* This key may be used to identify the context or specific type of feedback.
|
||||
*
|
||||
* @return the key for the feedback message.
|
||||
*/
|
||||
@Param(1)
|
||||
String key();
|
||||
|
||||
/**
|
||||
* Gets the feedback message that will be sent in response to the command.
|
||||
* The message is represented by a {@link Component}, which allows for rich text formatting.
|
||||
*
|
||||
* @return the feedback message to be displayed or logged.
|
||||
*/
|
||||
@Param(2)
|
||||
Component message();
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.event;
|
||||
|
||||
import net.momirealms.customnameplates.common.event.bus.EventBus;
|
||||
import net.momirealms.customnameplates.common.plugin.NameplatesPlugin;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
|
||||
/**
|
||||
* Interface for managing and dispatching events within the Nameplates plugin system.
|
||||
* <p>
|
||||
* This interface provides methods to subscribe to events, dispatch events, and interact with the underlying
|
||||
* {@link EventBus}. It allows plugins to register subscribers for specific events and manage the event lifecycle.
|
||||
* </p>
|
||||
*/
|
||||
public interface EventManager {
|
||||
|
||||
/**
|
||||
* A static inner class that holds the singleton instance of {@link EventManager}.
|
||||
* This ensures that the {@link EventManager} is initialized only once.
|
||||
*/
|
||||
class SingletonHolder {
|
||||
private static EventManager INSTANCE = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns the singleton instance of {@link EventManager}.
|
||||
* <p>
|
||||
* This method ensures that only one instance of the {@link EventManager} is created during the lifecycle
|
||||
* of the plugin. If the instance does not exist, it initializes the {@link EventManager} using the provided
|
||||
* {@link NameplatesPlugin}.
|
||||
* </p>
|
||||
*
|
||||
* @param plugin the {@link NameplatesPlugin} instance to be used for initializing the event manager
|
||||
* @return the singleton instance of {@link EventManager}
|
||||
*/
|
||||
static EventManager create(NameplatesPlugin plugin) {
|
||||
if (SingletonHolder.INSTANCE == null) {
|
||||
SingletonHolder.INSTANCE = new EventManagerImpl(plugin);
|
||||
}
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes a {@link EventSubscriber} to an event type.
|
||||
* <p>
|
||||
* This method allows subscribing a listener (subscriber) to a specific event type. The subscriber will be notified
|
||||
* whenever the event is dispatched.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of event to subscribe to
|
||||
* @param event the {@link Class} object representing the event type
|
||||
* @param subscriber the {@link EventSubscriber} that will handle the event
|
||||
* @return an {@link EventSubscription} representing the subscription
|
||||
*/
|
||||
<T extends NameplatesEvent> EventSubscription<T> subscribe(Class<T> event, EventSubscriber<? super T> subscriber);
|
||||
|
||||
/**
|
||||
* Subscribes a {@link EventSubscriber} to an event type with a custom event configuration.
|
||||
* <p>
|
||||
* This method allows subscribing a listener (subscriber) to a specific event type with additional configuration
|
||||
* settings for the event. The subscriber will be notified based on the provided configuration when the event is
|
||||
* dispatched.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of event to subscribe to
|
||||
* @param event the {@link Class} object representing the event type
|
||||
* @param config the {@link EventConfig} containing additional event configuration
|
||||
* @param subscriber the {@link EventSubscriber} that will handle the event
|
||||
* @return an {@link EventSubscription} representing the subscription
|
||||
*/
|
||||
<T extends NameplatesEvent> EventSubscription<T> subscribe(Class<T> event, EventConfig config, EventSubscriber<? super T> subscriber);
|
||||
|
||||
/**
|
||||
* Dispatches an event of the specified class with the provided parameters.
|
||||
* <p>
|
||||
* This method triggers the event, notifying all subscribers of the event. The event is dispatched synchronously
|
||||
* to all registered subscribers.
|
||||
* </p>
|
||||
*
|
||||
* @param eventClass the {@link Class} object representing the event type
|
||||
* @param params the parameters to pass to the event
|
||||
* @return the dispatched {@link NameplatesEvent}
|
||||
*/
|
||||
NameplatesEvent dispatch(Class<? extends NameplatesEvent> eventClass, Object... params);
|
||||
|
||||
/**
|
||||
* Dispatches an event of the specified class with the provided order and parameters.
|
||||
* <p>
|
||||
* This method allows dispatching the event with an optional order. The order is used to prioritize events,
|
||||
* allowing certain events to be processed before others. If the order is not provided, the event will be dispatched
|
||||
* without any specific order.
|
||||
* </p>
|
||||
*
|
||||
* @param eventClass the {@link Class} object representing the event type
|
||||
* @param order the optional {@link OptionalInt} specifying the order of the event
|
||||
* @param params the parameters to pass to the event
|
||||
* @return the dispatched {@link NameplatesEvent}
|
||||
*/
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
NameplatesEvent dispatch(Class<? extends NameplatesEvent> eventClass, OptionalInt order, Object... params);
|
||||
|
||||
/**
|
||||
* Retrieves the underlying event bus that handles event dispatching and subscriptions.
|
||||
* <p>
|
||||
* The {@link EventBus} is responsible for managing the lifecycle of events, including dispatching and subscribing
|
||||
* to events. This method allows direct access to the {@link EventBus}.
|
||||
* </p>
|
||||
*
|
||||
* @return the underlying {@link EventBus} used by the event manager
|
||||
*/
|
||||
EventBus<?> getEventBus();
|
||||
}
|
||||
@@ -3,10 +3,15 @@ package net.momirealms.customnameplates.common.event;
|
||||
import net.momirealms.customnameplates.common.plugin.NameplatesPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Interface for Nameplates Event
|
||||
*/
|
||||
public interface NameplatesEvent {
|
||||
|
||||
/**
|
||||
* Get the plugin instance this event was dispatched from
|
||||
*
|
||||
* @return the plugin instance
|
||||
*/
|
||||
@NotNull
|
||||
NameplatesPlugin plugin();
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.event.gen;
|
||||
|
||||
import net.momirealms.customnameplates.common.event.NameplatesEvent;
|
||||
import net.momirealms.customnameplates.common.plugin.NameplatesPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
/**
|
||||
* Abstract base class for events in the Nameplates plugin system.
|
||||
*/
|
||||
public abstract class AbstractNameplatesEvent implements NameplatesEvent {
|
||||
|
||||
private final NameplatesPlugin plugin;
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@code AbstractNameplatesEvent} with the given {@link NameplatesPlugin}.
|
||||
*
|
||||
* @param plugin the {@link NameplatesPlugin} instance associated with this event
|
||||
*/
|
||||
protected AbstractNameplatesEvent(NameplatesPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link NameplatesPlugin} instance associated with this event.
|
||||
*
|
||||
* @return the plugin instance
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public NameplatesPlugin plugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link MethodHandles.Lookup} instance for dynamic method invocation.
|
||||
* <p>
|
||||
* This method is currently unsupported and will throw an {@link UnsupportedOperationException} if invoked.
|
||||
* It may be overridden in subclasses to provide custom logic for dynamic method handles.
|
||||
* </p>
|
||||
*
|
||||
* @return the {@link MethodHandles.Lookup} instance
|
||||
* @throws UnsupportedOperationException if the method is not overridden in a subclass
|
||||
*/
|
||||
public MethodHandles.Lookup mhl() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,9 @@ import java.util.Map;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.*;
|
||||
|
||||
/**
|
||||
* A class for generating event class
|
||||
*/
|
||||
public class EventGenerator {
|
||||
|
||||
/**
|
||||
@@ -25,6 +25,10 @@ import org.incendo.cloud.minecraft.extras.caption.ComponentCaptionFormatter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* CustomNameplatesCaptionFormatter
|
||||
* @param <C> sender
|
||||
*/
|
||||
public class CustomNameplatesCaptionFormatter<C> implements ComponentCaptionFormatter<C> {
|
||||
|
||||
@Override
|
||||
@@ -19,9 +19,29 @@ package net.momirealms.customnameplates.common.locale;
|
||||
|
||||
import org.incendo.cloud.caption.Caption;
|
||||
|
||||
/**
|
||||
* A utility class that defines keys for various captions used in the Custom Nameplates plugin.
|
||||
* <p>
|
||||
* This class provides static final constants for common caption keys that are used for
|
||||
* error messages, argument parsing failures, and other localized messages in the plugin.
|
||||
* These keys can be used with a captioning system to retrieve appropriate translations
|
||||
* based on the user's locale.
|
||||
* </p>
|
||||
*/
|
||||
public final class CustomNameplatesCaptionKeys {
|
||||
|
||||
/**
|
||||
* Caption key for a failure when parsing a time argument.
|
||||
* This key is used for error messages related to time arguments that failed to parse.
|
||||
*/
|
||||
public static final Caption ARGUMENT_PARSE_FAILURE_TIME = Caption.of("argument.parse.failure.time");
|
||||
/**
|
||||
* Caption key for a failure when parsing a URL argument.
|
||||
* This key is used for error messages related to URL arguments that failed to parse.
|
||||
*/
|
||||
public static final Caption ARGUMENT_PARSE_FAILURE_URL = Caption.of("argument.parse.failure.url");
|
||||
/**
|
||||
* Caption key for a failure when parsing a named text color argument.
|
||||
* This key is used for error messages related to named text color arguments that failed to parse.
|
||||
*/
|
||||
public static final Caption ARGUMENT_PARSE_FAILURE_NAMEDTEXTCOLOR = Caption.of("argument.parse.failure.namedtextcolor");
|
||||
}
|
||||
@@ -21,6 +21,16 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.incendo.cloud.caption.CaptionProvider;
|
||||
import org.incendo.cloud.caption.DelegatingCaptionProvider;
|
||||
|
||||
/**
|
||||
* A custom implementation of a {@link CaptionProvider} for the Custom Nameplates plugin.
|
||||
* <p>
|
||||
* This class provides a caption provider that delegates to a constant provider which includes
|
||||
* predefined captions for argument parsing failure messages. It ensures that specific caption keys,
|
||||
* such as those related to parsing time, URL, and named text color arguments, are available for use.
|
||||
* </p>
|
||||
*
|
||||
* @param <C> the context type associated with the captions
|
||||
*/
|
||||
public final class CustomNameplatesCaptionProvider<C> extends DelegatingCaptionProvider<C> {
|
||||
|
||||
private static final CaptionProvider<?> PROVIDER = CaptionProvider.constantProvider()
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* A utility class for loading and retrieving properties from a custom properties file.
|
||||
* <p>
|
||||
* This class loads the properties from the {@code custom-nameplates.properties} file
|
||||
* located in the classpath and provides a way to retrieve property values by key.
|
||||
* The properties are loaded and stored in a singleton instance to ensure only
|
||||
* one loading of the properties file throughout the lifetime of the application.
|
||||
* </p>
|
||||
*/
|
||||
public class CustomNameplatesProperties {
|
||||
|
||||
/**
|
||||
* A map that holds the key-value pairs of properties.
|
||||
*/
|
||||
private final HashMap<String, String> propertyMap;
|
||||
|
||||
/**
|
||||
* Private constructor that initializes the property map.
|
||||
*
|
||||
* @param propertyMap the map holding the property key-value pairs
|
||||
*/
|
||||
private CustomNameplatesProperties(HashMap<String, String> propertyMap) {
|
||||
this.propertyMap = propertyMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value of a property based on the provided key.
|
||||
* <p>
|
||||
* This method throws a {@link RuntimeException} if the key is not found in the properties file.
|
||||
* </p>
|
||||
*
|
||||
* @param key the property key to retrieve
|
||||
* @return the value associated with the given key
|
||||
* @throws RuntimeException if the key is unknown or not found in the properties file
|
||||
*/
|
||||
public static String getValue(String key) {
|
||||
if (!SingletonHolder.INSTANCE.propertyMap.containsKey(key)) {
|
||||
throw new RuntimeException("Unknown key: " + key);
|
||||
}
|
||||
return SingletonHolder.INSTANCE.propertyMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* A static inner class to hold the singleton instance of {@link CustomNameplatesProperties}.
|
||||
* This class is used to lazily load the properties file and ensure only one instance is created.
|
||||
*/
|
||||
private static class SingletonHolder {
|
||||
|
||||
/**
|
||||
* The singleton instance of {@link CustomNameplatesProperties}.
|
||||
*/
|
||||
private static final CustomNameplatesProperties INSTANCE = getInstance();
|
||||
|
||||
/**
|
||||
* Loads the properties file and creates an instance of {@link CustomNameplatesProperties}.
|
||||
*
|
||||
* @return an instance of {@link CustomNameplatesProperties} containing the loaded properties
|
||||
* @throws RuntimeException if there is an error reading the properties file
|
||||
*/
|
||||
private static CustomNameplatesProperties getInstance() {
|
||||
try (InputStream inputStream = CustomNameplatesProperties.class.getClassLoader().getResourceAsStream("custom-nameplates.properties")) {
|
||||
HashMap<String, String> versionMap = new HashMap<>();
|
||||
Properties properties = new Properties();
|
||||
properties.load(inputStream);
|
||||
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
|
||||
if (entry.getKey() instanceof String key && entry.getValue() instanceof String value) {
|
||||
versionMap.put(key, value);
|
||||
}
|
||||
}
|
||||
return new CustomNameplatesProperties(versionMap);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error loading properties file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,12 @@ import java.nio.file.Path;
|
||||
*/
|
||||
public interface ClassPathAppender extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* Adds a JAR file to the classpath.
|
||||
*
|
||||
* @param file the {@link Path} to the JAR file to be added to the classpath.
|
||||
* @throws IllegalArgumentException if the provided file is not a valid JAR file.
|
||||
*/
|
||||
void addJarToClasspath(Path file);
|
||||
|
||||
@Override
|
||||
@@ -47,6 +47,20 @@ public interface ConfigLoader {
|
||||
*/
|
||||
YamlDocument loadConfig(String filePath, char routeSeparator);
|
||||
|
||||
/**
|
||||
* Loads a YAML configuration file from the specified file path with custom settings.
|
||||
* <p>
|
||||
* This method allows loading a YAML file with various settings, including general,
|
||||
* loader, dumper, and updater settings, providing more flexibility in how the file is processed.
|
||||
* </p>
|
||||
*
|
||||
* @param filePath the path to the configuration file.
|
||||
* @param generalSettings the general settings to use for loading the configuration.
|
||||
* @param loaderSettings the loader-specific settings to be applied.
|
||||
* @param dumperSettings the dumper-specific settings to be applied.
|
||||
* @param updaterSettings the updater-specific settings to be applied.
|
||||
* @return the loaded {@link YamlDocument} representing the YAML data.
|
||||
*/
|
||||
YamlDocument loadConfig(String filePath, GeneralSettings generalSettings, LoaderSettings loaderSettings, DumperSettings dumperSettings, UpdaterSettings updaterSettings);
|
||||
|
||||
/**
|
||||
@@ -17,19 +17,34 @@
|
||||
|
||||
package net.momirealms.customnameplates.common.plugin.feature;
|
||||
|
||||
/**
|
||||
* Interface for objects that can be reloaded, unloaded, and loaded again.
|
||||
*/
|
||||
public interface Reloadable {
|
||||
|
||||
/**
|
||||
* Reloads the feature or component by first unloading it and then loading it again.
|
||||
*/
|
||||
default void reload() {
|
||||
unload();
|
||||
load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unloads the feature or component.
|
||||
*/
|
||||
default void unload() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the feature or component.
|
||||
*/
|
||||
default void load() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the feature or component by unloading it.
|
||||
*/
|
||||
default void disable() {
|
||||
unload();
|
||||
}
|
||||
@@ -45,6 +45,10 @@ public abstract class AbstractJavaScheduler<T> implements SchedulerAdapter<T> {
|
||||
private final ScheduledThreadPoolExecutor scheduler;
|
||||
private final ForkJoinPool worker;
|
||||
|
||||
/**
|
||||
* Constructs an AbstractJavaScheduler
|
||||
* @param plugin plugin
|
||||
*/
|
||||
public AbstractJavaScheduler(NameplatesPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
@@ -19,19 +19,45 @@ package net.momirealms.customnameplates.common.plugin.scheduler;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
/**
|
||||
* Represents an asynchronous task that is scheduled to run at a later time.
|
||||
* This class wraps a {@link ScheduledFuture} and provides methods to cancel
|
||||
* the task and check if it has been cancelled.
|
||||
*/
|
||||
public class AsyncTask implements SchedulerTask {
|
||||
|
||||
/**
|
||||
* The {@link ScheduledFuture} representing the scheduled task.
|
||||
* This is used to interact with the task, such as cancelling it.
|
||||
*/
|
||||
private final ScheduledFuture<?> future;
|
||||
|
||||
/**
|
||||
* Constructs an {@link AsyncTask} using the provided {@link ScheduledFuture}.
|
||||
*
|
||||
* @param future the {@link ScheduledFuture} representing the scheduled task.
|
||||
*/
|
||||
public AsyncTask(ScheduledFuture<?> future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the scheduled task. The task will not run if it has not started yet,
|
||||
* or it will stop if it is currently running.
|
||||
*
|
||||
* @see ScheduledFuture#cancel(boolean)
|
||||
*/
|
||||
@Override
|
||||
public void cancel() {
|
||||
future.cancel(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the task has been cancelled.
|
||||
*
|
||||
* @return true if the task has been cancelled, false otherwise.
|
||||
* @see ScheduledFuture#isCancelled()
|
||||
*/
|
||||
@Override
|
||||
public boolean cancelled() {
|
||||
return future.isCancelled();
|
||||
@@ -60,6 +60,7 @@ public interface SchedulerAdapter<T> {
|
||||
* Executes a task sync
|
||||
*
|
||||
* @param task the task
|
||||
* @param location the location
|
||||
*/
|
||||
default void executeSync(Runnable task, T location) {
|
||||
sync().run(task, location);
|
||||
@@ -83,6 +84,7 @@ public interface SchedulerAdapter<T> {
|
||||
* Executes the given task repeatedly at a given interval.
|
||||
*
|
||||
* @param task the task
|
||||
* @param delay the delay
|
||||
* @param interval the interval
|
||||
* @param unit the unit of interval
|
||||
* @return the resultant task instance
|
||||
@@ -35,5 +35,10 @@ public interface SchedulerTask {
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Check if the task is cancelled
|
||||
*
|
||||
* @return cancelled or not
|
||||
*/
|
||||
boolean cancelled();
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public interface Sender {
|
||||
boolean isConsole();
|
||||
|
||||
/**
|
||||
* Gets whether this sender is still valid & receiving messages.
|
||||
* Gets whether this sender is still valid and receiving messages.
|
||||
*
|
||||
* @return if this sender is valid
|
||||
*/
|
||||
@@ -19,30 +19,95 @@ package net.momirealms.customnameplates.common.util;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Enum representing the supported system architectures.
|
||||
* This enum helps determine the architecture of the current system
|
||||
* and provides utility methods for architecture-related operations.
|
||||
* <p>
|
||||
* The possible architectures include:
|
||||
* - X64 (64-bit x86)
|
||||
* - X86 (32-bit x86)
|
||||
* - ARM64 (64-bit ARM)
|
||||
* - ARM32 (32-bit ARM)
|
||||
* - PPC64LE (64-bit PowerPC, Little Endian)
|
||||
* - RISCV64 (64-bit RISC-V)
|
||||
* <p>
|
||||
* It also provides a utility method to get the native path representation of the architecture
|
||||
* and a method to retrieve the current architecture of the system.
|
||||
*/
|
||||
public enum Architecture {
|
||||
|
||||
/**
|
||||
* Represents a 64-bit x86 architecture.
|
||||
*/
|
||||
X64(true),
|
||||
|
||||
/**
|
||||
* Represents a 32-bit x86 architecture.
|
||||
*/
|
||||
X86(false),
|
||||
|
||||
/**
|
||||
* Represents a 64-bit ARM architecture.
|
||||
*/
|
||||
ARM64(true),
|
||||
|
||||
/**
|
||||
* Represents a 32-bit ARM architecture.
|
||||
*/
|
||||
ARM32(false),
|
||||
|
||||
/**
|
||||
* Represents a 64-bit PowerPC Little Endian architecture.
|
||||
* Only 'ppc64le' is supported in this case.
|
||||
*/
|
||||
PPC64LE(true),
|
||||
|
||||
/**
|
||||
* Represents a 64-bit RISC-V architecture.
|
||||
* Only 'riscv64' is supported in this case.
|
||||
*/
|
||||
RISCV64(true);
|
||||
|
||||
/**
|
||||
* The current architecture of the system, determined during class initialization.
|
||||
*/
|
||||
static final Architecture current;
|
||||
|
||||
/**
|
||||
* A boolean flag indicating if the architecture is 64-bit.
|
||||
*/
|
||||
final boolean is64Bit;
|
||||
|
||||
/**
|
||||
* Constructor to initialize the architecture with its 64-bit flag.
|
||||
*
|
||||
* @param is64Bit a boolean indicating if the architecture is 64-bit.
|
||||
*/
|
||||
Architecture(boolean is64Bit) {
|
||||
this.is64Bit = is64Bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the native path representation of the architecture.
|
||||
* The name is returned in lowercase using English locale.
|
||||
*
|
||||
* @return the native path for the architecture (e.g., "x64", "arm64").
|
||||
*/
|
||||
public String getNativePath() {
|
||||
return name().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current architecture of the system.
|
||||
*
|
||||
* @return the current system architecture as an {@link Architecture} enum.
|
||||
*/
|
||||
public static Architecture get() {
|
||||
return current;
|
||||
}
|
||||
|
||||
// Static block to determine the current system architecture based on system properties.
|
||||
static {
|
||||
String osArch = System.getProperty("os.arch");
|
||||
boolean is64Bit = osArch.contains("64") || osArch.startsWith("armv8");
|
||||
@@ -1,26 +1,18 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.util;
|
||||
@@ -28,15 +20,7 @@ package net.momirealms.customnameplates.common.util;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents three different states of a setting.
|
||||
*
|
||||
* <p>Possible values:</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@link #TRUE} - a positive setting</li>
|
||||
* <li>{@link #FALSE} - a negative (negated) setting</li>
|
||||
* <li>{@link #UNDEFINED} - a non-existent setting</li>
|
||||
* </ul>
|
||||
* Tristate
|
||||
*/
|
||||
public enum Tristate {
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
plugins {
|
||||
id("io.github.goooler.shadow") version "8.1.8"
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(project(":common"))
|
||||
compileOnly(project(":api"))
|
||||
// YAML
|
||||
compileOnly("dev.dejvokep:boosted-yaml:${rootProject.properties["boosted_yaml_version"]}")
|
||||
|
||||
@@ -3,6 +3,7 @@ import java.io.ByteArrayOutputStream
|
||||
|
||||
plugins {
|
||||
id("java")
|
||||
id("com.gradleup.shadow") version "9.0.0-beta6"
|
||||
}
|
||||
|
||||
val git : String = versionBanner()
|
||||
@@ -11,9 +12,8 @@ ext["git_version"] = git
|
||||
ext["builder"] = builder
|
||||
|
||||
subprojects {
|
||||
|
||||
apply(plugin = "java")
|
||||
apply(plugin = "java-library")
|
||||
apply(plugin = "com.gradleup.shadow")
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
42
common/.gitignore
vendored
42
common/.gitignore
vendored
@@ -1,42 +0,0 @@
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
@@ -1,37 +0,0 @@
|
||||
repositories {
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("net.kyori:adventure-api:${rootProject.properties["adventure_bundle_version"]}") {
|
||||
exclude(module = "adventure-bom")
|
||||
exclude(module = "checker-qual")
|
||||
exclude(module = "annotations")
|
||||
}
|
||||
compileOnly("org.incendo:cloud-core:${rootProject.properties["cloud_core_version"]}")
|
||||
compileOnly("org.incendo:cloud-minecraft-extras:${rootProject.properties["cloud_minecraft_extras_version"]}")
|
||||
compileOnly("dev.dejvokep:boosted-yaml:${rootProject.properties["boosted_yaml_version"]}")
|
||||
compileOnly("org.jetbrains:annotations:${rootProject.properties["jetbrains_annotations_version"]}")
|
||||
compileOnly("org.slf4j:slf4j-api:${rootProject.properties["slf4j_version"]}")
|
||||
compileOnly("org.apache.logging.log4j:log4j-core:${rootProject.properties["log4j_version"]}")
|
||||
compileOnly("net.kyori:adventure-text-minimessage:${rootProject.properties["adventure_bundle_version"]}")
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:${rootProject.properties["adventure_bundle_version"]}")
|
||||
compileOnly("com.github.ben-manes.caffeine:caffeine:${rootProject.properties["caffeine_version"]}")
|
||||
compileOnly("com.google.code.gson:gson:${rootProject.properties["gson_version"]}")
|
||||
compileOnly("net.objecthunter:exp4j:${rootProject.properties["exp4j_version"]}")
|
||||
compileOnly("net.bytebuddy:byte-buddy:${rootProject.properties["byte_buddy_version"]}")
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(17)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.encoding = "UTF-8"
|
||||
options.release.set(17)
|
||||
dependsOn(tasks.clean)
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.command;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.momirealms.customnameplates.common.sender.SenderFactory;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
|
||||
public abstract class AbstractCommandFeature<C> implements CommandFeature<C> {
|
||||
|
||||
protected final CustomNameplatesCommandManager<C> commandManager;
|
||||
protected CommandConfig<C> commandConfig;
|
||||
|
||||
public AbstractCommandFeature(CustomNameplatesCommandManager<C> commandManager) {
|
||||
this.commandManager = commandManager;
|
||||
}
|
||||
|
||||
protected abstract SenderFactory<?, C> getSenderFactory();
|
||||
|
||||
public abstract Command.Builder<? extends C> assembleCommand(CommandManager<C> manager, Command.Builder<C> builder);
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Command<C> registerCommand(CommandManager<C> manager, Command.Builder<C> builder) {
|
||||
Command<C> command = (Command<C>) assembleCommand(manager, builder).build();
|
||||
manager.command(command);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerRelatedFunctions() {
|
||||
// empty
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterRelatedFunctions() {
|
||||
// empty
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void handleFeedback(CommandContext<?> context, TranslatableComponent.Builder key, Component... args) {
|
||||
if (context.flags().hasFlag("silent")) {
|
||||
return;
|
||||
}
|
||||
commandManager.handleCommandFeedback((C) context.sender(), key, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleFeedback(C sender, TranslatableComponent.Builder key, Component... args) {
|
||||
commandManager.handleCommandFeedback(sender, key, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomNameplatesCommandManager<C> getCustomNameplatesCommandManager() {
|
||||
return commandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfig<C> getCommandConfig() {
|
||||
return commandConfig;
|
||||
}
|
||||
|
||||
public void setCommandConfig(CommandConfig<C> commandConfig) {
|
||||
this.commandConfig = commandConfig;
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.command;
|
||||
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
|
||||
public interface CommandBuilder<C> {
|
||||
|
||||
CommandBuilder<C> setPermission(String permission);
|
||||
|
||||
CommandBuilder<C> setCommandNode(String... subNodes);
|
||||
|
||||
Command.Builder<C> getBuiltCommandBuilder();
|
||||
|
||||
class BasicCommandBuilder<C> implements CommandBuilder<C> {
|
||||
|
||||
private Command.Builder<C> commandBuilder;
|
||||
|
||||
public BasicCommandBuilder(CommandManager<C> commandManager, String rootNode) {
|
||||
this.commandBuilder = commandManager.commandBuilder(rootNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandBuilder<C> setPermission(String permission) {
|
||||
this.commandBuilder = this.commandBuilder.permission(permission);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandBuilder<C> setCommandNode(String... subNodes) {
|
||||
for (String sub : subNodes) {
|
||||
this.commandBuilder = this.commandBuilder.literal(sub);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command.Builder<C> getBuiltCommandBuilder() {
|
||||
return commandBuilder;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CommandConfig<C> {
|
||||
|
||||
private boolean enable = false;
|
||||
private List<String> usages = new ArrayList<>();
|
||||
private String permission = null;
|
||||
|
||||
private CommandConfig() {
|
||||
}
|
||||
|
||||
public CommandConfig(boolean enable, List<String> usages, String permission) {
|
||||
this.enable = enable;
|
||||
this.usages = usages;
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
public boolean isEnable() {
|
||||
return enable;
|
||||
}
|
||||
|
||||
public List<String> getUsages() {
|
||||
return usages;
|
||||
}
|
||||
|
||||
public String getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
public static class Builder<C> {
|
||||
|
||||
private final CommandConfig<C> config;
|
||||
|
||||
public Builder() {
|
||||
this.config = new CommandConfig<>();
|
||||
}
|
||||
|
||||
public Builder<C> usages(List<String> usages) {
|
||||
config.usages = usages;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<C> permission(String permission) {
|
||||
config.permission = permission;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<C> enable(boolean enable) {
|
||||
config.enable = enable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandConfig<C> build() {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.command;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
|
||||
public interface CommandFeature<C> {
|
||||
|
||||
Command<C> registerCommand(CommandManager<C> cloudCommandManager, Command.Builder<C> builder);
|
||||
|
||||
String getFeatureID();
|
||||
|
||||
void registerRelatedFunctions();
|
||||
|
||||
void unregisterRelatedFunctions();
|
||||
|
||||
void handleFeedback(CommandContext<?> context, TranslatableComponent.Builder key, Component... args);
|
||||
|
||||
void handleFeedback(C sender, TranslatableComponent.Builder key, Component... args);
|
||||
|
||||
CustomNameplatesCommandManager<C> getCustomNameplatesCommandManager();
|
||||
|
||||
CommandConfig<C> getCommandConfig();
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.command;
|
||||
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.util.Index;
|
||||
import net.momirealms.customnameplates.common.util.TriConsumer;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface CustomNameplatesCommandManager<C> {
|
||||
|
||||
String commandsFile = "commands.yml";
|
||||
|
||||
void unregisterFeatures();
|
||||
|
||||
void registerFeature(CommandFeature<C> feature, CommandConfig<C> config);
|
||||
|
||||
void registerDefaultFeatures();
|
||||
|
||||
Index<String, CommandFeature<C>> getFeatures();
|
||||
|
||||
void setFeedbackConsumer(@NotNull TriConsumer<C, String, Component> feedbackConsumer);
|
||||
|
||||
TriConsumer<C, String, Component> defaultFeedbackConsumer();
|
||||
|
||||
CommandConfig<C> getCommandConfig(YamlDocument document, String featureID);
|
||||
|
||||
Collection<Command.Builder<C>> buildCommandBuilders(CommandConfig<C> config);
|
||||
|
||||
CommandManager<C> getCommandManager();
|
||||
|
||||
void handleCommandFeedback(C sender, TranslatableComponent.Builder key, Component... args);
|
||||
|
||||
void handleCommandFeedback(C sender, String node, Component component);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package net.momirealms.customnameplates.common.event;
|
||||
|
||||
public interface Cancellable {
|
||||
|
||||
/**
|
||||
* Gets the cancelled state.
|
||||
*/
|
||||
boolean cancelled();
|
||||
|
||||
/**
|
||||
* Sets the cancelled state.
|
||||
*/
|
||||
void cancelled(final boolean cancelled);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package net.momirealms.customnameplates.common.event;
|
||||
|
||||
import net.momirealms.customnameplates.common.event.bus.EventBus;
|
||||
import net.momirealms.customnameplates.common.plugin.NameplatesPlugin;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
|
||||
public interface EventManager {
|
||||
|
||||
class SingletonHolder {
|
||||
private static EventManager INSTANCE = null;
|
||||
}
|
||||
|
||||
static EventManager create(NameplatesPlugin plugin) {
|
||||
if (SingletonHolder.INSTANCE == null) {
|
||||
SingletonHolder.INSTANCE = new EventManagerImpl(plugin);
|
||||
}
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
<T extends NameplatesEvent> EventSubscription<T> subscribe(Class<T> event, EventSubscriber<? super T> subscriber);
|
||||
|
||||
<T extends NameplatesEvent> EventSubscription<T> subscribe(Class<T> event, EventConfig config, EventSubscriber<? super T> subscriber);
|
||||
|
||||
NameplatesEvent dispatch(Class<? extends NameplatesEvent> eventClass, Object... params);
|
||||
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
NameplatesEvent dispatch(Class<? extends NameplatesEvent> eventClass, OptionalInt order, Object... params);
|
||||
|
||||
EventBus<?> getEventBus();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user