Rework player and command handling + new stuff

This commit is contained in:
JeremyStar™ 2024-11-16 00:25:34 +01:00
parent 2d615d717d
commit c69fc81a87
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
40 changed files with 2818 additions and 908 deletions

View file

@ -19,6 +19,8 @@
package de.jeremystartm.pickshadow.extension; package de.jeremystartm.pickshadow.extension;
import de.jeremystartm.pickshadow.extension.misc.TabListHandler;
import net.luckperms.api.util.Tristate;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -36,10 +38,58 @@ import java.util.List;
* @since v1-release0 * @since v1-release0
*/ */
public final class BuildOptions { public final class BuildOptions {
// -----> Links
/**
* Contains the link to the repository
* hosting PickShadow's server-side code.
*
* @since v1-release0
*/
public static final @NotNull String LINKS_PICKSHADOW_WEBSITE = "";
/**
* Contains the link to the repository
* hosting PickShadow's server-side code.
*
* @since v1-release0
*/
public static final @NotNull String LINKS_PICKSHADOW_FORUM = "";
/**
* Contains the link to the repository
* hosting PickShadow's server-side code.
*
* @since v1-release0
*/
public static final @NotNull String LINKS_PICKSHADOW_REPOSITORY = "https://git.staropensource.de/JeremyStarTM/PickShadow";
/**
* Contains the link to LuckPerms' website.
*
* @since v1-release0
*/
public static final @NotNull String LINKS_LUCKPERMS = "https://luckperms.net";
/**
* Contains the link to ViaVersions' website.
*
* @since v1-release0
*/
public static final @NotNull String LINKS_VIAVERSION = "https://viaversion.com";
/**
* Contains the link to FreedomChat's Modrinth site.
*
* @since v1-release0
*/
public static final @NotNull String LINKS_FREEDOMCHAT = "https://modrinth.com/plugin/freedomchat";
// -----> Settings // -----> Settings
/** /**
* Contains an array of all bad effects. * An array containing all bad effects.
* *
* @see PotionEffectType
* @since v1-release0 * @since v1-release0
*/ */
public static final @NotNull List<@NotNull PotionEffectType> SETTINGS_EFFECTS_BAD = List.of( public static final @NotNull List<@NotNull PotionEffectType> SETTINGS_EFFECTS_BAD = List.of(
@ -58,9 +108,11 @@ public final class BuildOptions {
PotionEffectType.RAID_OMEN, PotionEffectType.RAID_OMEN,
PotionEffectType.INFESTED PotionEffectType.INFESTED
); );
/** /**
* Contains an array of all damaging effects. * An array containing all damaging effects.
* *
* @see PotionEffectType
* @since v1-release0 * @since v1-release0
*/ */
public static final @NotNull List<@NotNull PotionEffectType> SETTINGS_EFFECTS_DAMAGING = List.of( public static final @NotNull List<@NotNull PotionEffectType> SETTINGS_EFFECTS_DAMAGING = List.of(
@ -69,6 +121,15 @@ public final class BuildOptions {
PotionEffectType.POISON PotionEffectType.POISON
); );
/**
* The rate at which the tab list shall be updated.
*
* @see TabListHandler
* @since v1-release0
*/
public static final long SETTINGS_TABLIST_UPDATERATE = 20L;
// -----> Fixes and unfixes // -----> Fixes and unfixes
/** /**
* Unfixes MC-212 (fixed in 24w45a), * Unfixes MC-212 (fixed in 24w45a),
@ -82,6 +143,7 @@ public final class BuildOptions {
*/ */
public static final boolean UNFIX_FALLDAMAGE_CANCELLING = true; public static final boolean UNFIX_FALLDAMAGE_CANCELLING = true;
// -----> Small stuff // -----> Small stuff
/** /**
* Hides all messages starting with {@code #}. * Hides all messages starting with {@code #}.
@ -105,4 +167,24 @@ public final class BuildOptions {
* @since v1-release0 * @since v1-release0
*/ */
public static final boolean SMALLSTUFF_STONECUTTER_DAMAGE = true; public static final boolean SMALLSTUFF_STONECUTTER_DAMAGE = true;
/**
* Determines if and how
* bats shall be killed.
* <p>
* {@link Tristate#TRUE} causes all bats to be killed.
* {@link Tristate#UNDEFINED} will kill all naturally spawned bats.
* {@link Tristate#FALSE} disables this setting.
*
* @since v1-release0
*/
public static final @NotNull Tristate SMALLSTUFF_KILL_BATS = Tristate.UNDEFINED;
/**
* Enables a faster walking
* if walking on a path block.
*
* @since v1-release0
*/
public static final boolean SMALLSTUFF_FASTER_PATH_WALKING = true;
} }

View file

@ -20,7 +20,6 @@
package de.jeremystartm.pickshadow.extension; package de.jeremystartm.pickshadow.extension;
import de.jeremystartm.pickshadow.common.CommonLibrary; import de.jeremystartm.pickshadow.common.CommonLibrary;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.jeremystartm.pickshadow.extension.command.general.AnnounceCommand; import de.jeremystartm.pickshadow.extension.command.general.AnnounceCommand;
import de.jeremystartm.pickshadow.extension.command.general.replacement.GamemodeCommand; import de.jeremystartm.pickshadow.extension.command.general.replacement.GamemodeCommand;
@ -97,7 +96,6 @@ public final class Extension extends JavaPlugin {
TranslationManager.loadTranslations(); TranslationManager.loadTranslations();
TranslationManager.processTranslations(); TranslationManager.processTranslations();
//TabListHandler.initialize(); //TabListHandler.initialize();
PlayerDataFactory.initialize();
Logger.info("Bootstrapped in " + Miscellaneous.measureExecutionTime(() -> {}) + "ms"); Logger.info("Bootstrapped in " + Miscellaneous.measureExecutionTime(() -> {}) + "ms");
} }
@ -132,7 +130,9 @@ public final class Extension extends JavaPlugin {
new ClearChatCommand(); new ClearChatCommand();
new ExtensionCommand(); new ExtensionCommand();
new LanguageCommand(); new LanguageCommand();
new LegacyExtensionCommand();
new LinkCommand(); new LinkCommand();
new SpeedCommand();
new TrollCommand(); new TrollCommand();
@ -150,8 +150,8 @@ public final class Extension extends JavaPlugin {
Logger.verb("Starting schedulers"); Logger.verb("Starting schedulers");
Bukkit.getServer().getGlobalRegionScheduler().runAtFixedRate(Extension.getInstance(), Scheduler::server, 1L, 1L); Bukkit.getServer().getGlobalRegionScheduler().runAtFixedRate(Extension.getInstance(), Scheduler::server, 1L, 1L);
}) + "ms"); }) + "ms");
} catch (Exception exception) { } catch (Throwable throwable) {
Logger.crash("Initialization failed", exception); Logger.crash("Initialization failed", throwable);
} }
} }

View file

@ -0,0 +1,453 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.extension.api.command;
import de.jeremystartm.pickshadow.extension.ExtensionConfiguration;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayerFactory;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.staropensource.engine.base.logging.Logger;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.craftbukkit.command.ServerCommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range;
import java.util.*;
import static java.util.Map.entry;
/**
* Abstract class for implementing commands.
*
* @see CommandForced
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public abstract class Command implements CommandExecutor {
/**
* Contains a list of all registered commands.
*
* @since v1-release0
*/
private static final @NotNull List<@NotNull Command> REGISTERED = new ArrayList<>();
/**
* Contains a {@link CommandExecutor} implementation
* for disabled commands (caused by a disabled mode).
*
* @see ExtensionConfiguration#getEnabledModes()
* @since v1-release0
*/
public static final @NotNull CommandExecutor disallowedExecutor = (sender, command, alias, arguments) -> {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_INVALID_MODE, sender, true));
return true;
};
/**
* Contains information about this command.
*
* @since v1-release0
* -- GETTER --
* Returns information about this command.
*
* @return command information
* @since v1-release0
*/
private final @NotNull Command.Information information;
// -----> Constructors
/**
* Initializes this abstract class
* and registers the command.
*
* @param information information about the command
* @param commands all commands this class should handle
* @throws IllegalArgumentException if a command does not exist
* @since v1-release0
*/
public Command(@NotNull Command.Information information, @NotNull String... commands) throws IllegalArgumentException {
boolean disallowedByMode = !Arrays.stream(ExtensionConfiguration.getInstance().getEnabledModes()).toList().contains(information.mode());
this.information = information;
for (String command : commands) {
PluginCommand pluginCommand = Bukkit.getPluginCommand(command);
if (pluginCommand == null)
throw new IllegalArgumentException("Command registration failed: The command \"" + command + "\" does not exist");
if (disallowedByMode) {
pluginCommand.setExecutor(disallowedExecutor);
pluginCommand.setTabCompleter(null);
} else {
pluginCommand.setExecutor(this);
pluginCommand.setTabCompleter(new TabCompleter() {
@Override
public @NotNull List<String> onTabComplete(@NotNull CommandSender sender, @NotNull org.bukkit.command.Command command, @NotNull String label, @NotNull String[] args) {
return StringUtil.copyPartialMatches(args[args.length - 1], getCompletion().complete(sender, label, args), new ArrayList<>());
}
});
}
}
REGISTERED.add(this);
}
/**
* Initializes this abstract class
* and registers the command.
* <p>
* Using this constructor instead of
* {@link #Command(Information, String...)}
* causes the creation of a dummy command
* which must be registered manually.
* Not recommended, use only when needed.
*
* @since v1-release0
*/
public Command(@NotNull Command.Information information) {
this.information = information;
REGISTERED.add(this);
}
// -----> Static methods
/**
* Returns a list of all registered commands.
*
* @return list of registered commands
* @since v1-release0
*/
public static List<@NotNull Command> getREGISTERED() {
return Collections.unmodifiableList(REGISTERED);
}
// -----> Getters
/**
* Provides tab completions for this command.
*
* @return completion
* @since v1-release0
*/
public abstract @NotNull TabCompletion getCompletion();
// -----> Command invocation
/**
* Required by the {@link CommandExecutor} interface.
*
* @deprecated use {@link #invoke(CommandSender, String, String[])} instead
* @see #invoke(CommandSender, String, String[])
* @since v1-release0
*/
@Deprecated
@Override
public final boolean onCommand(@NotNull CommandSender sender, @NotNull org.bukkit.command.Command command, @NotNull String alias, @NotNull String @NotNull [] arguments) {
invoke(sender, alias, arguments);
return true;
}
/**
* Executes this command.
*
* @since v1-release0
*/
public final void invoke(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] arguments) {
try {
invokeAll(sender, alias, arguments);
if (sender instanceof Player player)
invokePlayer(PSPlayerFactory.get(player), alias, arguments);
else if (sender instanceof ServerCommandSender consoleSender)
invokeConsole(consoleSender, alias, arguments);
else
throw new IllegalStateException("The command was neither executed by a player nor the server console");
} catch (Exception exception) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNKNOWN, sender, true));
Logger.crash(
"Command /"
+ information.name()
+ " (under alias /"
+ alias
+ ") failed for sender "
+ sender.getName()
+ " (console="
+ (sender instanceof ConsoleCommandSender)
+ ") with the following arguments:\n"
+ Arrays.toString(arguments),
exception,
false);
}
}
/**
* Command handler, regardless of whether the
* caller is a player or the server console.
*
* @param sender command sender which invoked this command
* @param alias alias used
* @param arguments command arguments
* @throws Exception on error
* @since v1-release0
*/
@SuppressWarnings("RedundantThrows")
protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] arguments) throws Exception {}
/**
* Command handler, invoked if the command
* has been invoked by the server console.
*
* @param console console command sender
* @param alias alias used
* @param arguments command arguments
* @throws Exception on error
* @since v1-release0
*/
@SuppressWarnings("RedundantThrows")
protected void invokeConsole(@NotNull ServerCommandSender console, @NotNull String alias, @NotNull String @NotNull [] arguments) throws Exception {
if (information.executionTarget == ExecutionTarget.PLAYERS_ONLY)
console.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, console, true));
}
/**
* Command handler, invoked if the
* command has been invoked by a player.
*
* @param player player which invoked this command
* @param alias alias used
* @param arguments command arguments
* @throws Exception on error
* @since v1-release0
*/
@SuppressWarnings("RedundantThrows")
protected void invokePlayer(@NotNull PSPlayer player, @NotNull String alias, @NotNull String @NotNull [] arguments) throws Exception {
if (information.executionTarget == ExecutionTarget.CONSOLE_ONLY)
player.messageTranslatable(LanguageString.ERROR_NOT_SERVER_CONSOLE, true);
}
// -----> Utility methods
/**
* Performs a permission check, sends the sender
* an error message and then returns.
* Useful for easy permission checks.
*
* @param sender sender to check
* @param permission permission to check for
* @return {@code true} if the permission is missing, {@code false} otherwise
* @since v1-release0
*/
protected static boolean checkPermission(@NotNull CommandSender sender, @NotNull String permission) {
if (sender instanceof ServerCommandSender)
return false;
if (!sender.hasPermission(permission)) {
sender.sendRichMessage(
TranslationManager.get(LanguageString.ERROR_MISSING_PERM, sender, true)
.replace("%permission%", permission)
);
return true;
}
return false;
}
/**
* Performs a permission check, sends the sender
* an error message and then returns.
* Useful for easy permission checks.
*
* @param player {@link PSPlayer} to check
* @param permission permission to check for
* @return {@code true} if the permission is missing, {@code false} otherwise
* @since v1-release0
*/
protected static boolean checkPermission(@NotNull PSPlayer player, @NotNull String permission) {
if (!player.hasPermission(permission)) {
player.messageTranslatable(
LanguageString.ERROR_MISSING_PERM,
true,
entry("permission", permission)
);
return true;
}
return false;
}
/**
* Determines the target player.
*
* @param sender command sender
* @param arguments array of arguments
* @param index index of the player name to check at
* @return target player and if the supplied command sender was used
* @throws IndexOutOfBoundsException if the size of {@code arguments} is smaller than the specified {@code index}
* @throws IllegalCallerException if no target was specified in {@code arguments} and the sender is the server console
* @throws IllegalArgumentException if the specified target in {@code arguments} is invalid or does not exist
* @since v1-release0
*/
public static @NotNull Map.Entry<@NotNull PSPlayer, @NotNull Boolean> determineTarget(@NotNull CommandSender sender, @NotNull String @NotNull [] arguments, int index) throws IndexOutOfBoundsException, IllegalCallerException, IllegalArgumentException {
if (arguments.length == index) {
if (sender instanceof Player bukkitPlayer)
return entry(PSPlayerFactory.get(bukkitPlayer), true);
else {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true));
throw new IllegalCallerException("No target player was specified and the command sender is the server console");
}
} else if (arguments.length > index) {
Player bukkitPlayer = Bukkit.getPlayer(arguments[index]);
PSPlayer player;
if (bukkitPlayer == null) {
sender.sendRichMessage(TranslationManager.get(
LanguageString.ERROR_PLAYER_NOT_FOUND,
sender,
true,
entry("player", arguments[index])
));
throw new IllegalArgumentException("The specified target player '" + arguments[index] + "' isn't online or is invalid");
} else
player = PSPlayerFactory.get(bukkitPlayer);
return entry(player, player.getUsername().equals(sender.getName()));
} else {
throw new IndexOutOfBoundsException("Size of 'arguments' is smaller than the specified 'index'");
}
}
// -----> Inner classes
/**
* Represents by whom a command can be used.
*
* @since v1-release0
*/
public enum ExecutionTarget {
/**
* Restricts the command to players only.
*
* @since v1-release0
*/
PLAYERS_ONLY,
/**
* Restricts the command to the server console only.
*
* @since v1-release0
*/
CONSOLE_ONLY,
/**
* Restricts certain actions of the command to players only.
*
* @since v1-release0
*/
CONSOLE_PARTIAL,
/**
* Restricts certain actions of the command to the server console only.
*
* @since v1-release0
*/
PLAYERS_PARTIAL,
/**
* Allows the command to be executed by players and the server console.
*
* @since v1-release0
*/
ALL
}
/**
* Provides information about a command.
*
* @param name Name of the command
* @param aliases Array of acceptable aliases
* @param description Description of the command
* @param syntax Syntax of the command
* @param mode Plugin mode of the command
* @param executionOrder Execution order in which the three execution methods shall be invoked.
* <p>
* Must contain exactly three elements, representing this order:
* <ol>
* <li>{@link #invokeAll(CommandSender, String, String[])}</li>
* <li>{@link #invokeConsole(ServerCommandSender, String, String[])}</li>
* <li>{@link #invokePlayer(PSPlayer, String, String[])}</li>
* </ol>
* Values are required to be between {@code 0} and {@code 2}, with
* each value being used only once.
* <p>
* Examples:
* <ul>
* <li>{@code new int[]{ 0, 2, 1 }}: 1. all, 2. player, 3. console</li>
* <li>{@code new int[]{ 2, 1, 0 }}: 1. player, 2. console, 3. all</li>
* <li>{@code new int[]{ 1, 2, 0 }}: 1. player, 2. all, 3. console</li>
* </ul>
* <p>
* If set to {@code null}, {@code new int[]{ 0, 1, 2 }} will be used.
* @param executionTarget information about who can execute the command
* @since v1-release0
*/
public record Information (
@NotNull String name,
@NotNull String @NotNull [] aliases,
@NotNull String description,
@NotNull String syntax,
@NotNull String mode,
@Range(from = 0, to = 2) int @Nullable [] executionOrder,
@NotNull Command.ExecutionTarget executionTarget
) {
/**
* Creates and initializes an
* instance of this record.
*/
public Information {
if (executionOrder == null)
executionOrder = new int[]{ 0, 1, 2 };
// Verify 'executionOrder'
// -> Amount of items
if (executionOrder.length != 3)
throw new IllegalStateException("'executionOrder' does not contain exactly three items");
// -> Bounds
if (
(executionOrder[0] < 0 || executionOrder[0] > 2)
|| (executionOrder[1] < 0 || executionOrder[1] > 2)
|| (executionOrder[2] < 0 || executionOrder[2] > 2)
)
throw new IllegalStateException("Some item in 'executionOrder' is either smaller than '0' or bigger than '2'");
// -> Duplicate values
if (
executionOrder[0] == executionOrder[1]
|| executionOrder[0] == executionOrder[2]
|| executionOrder[1] == executionOrder[2]
)
throw new IllegalStateException("Two or more items in 'executionOrder' have the same value");
}
}
}

View file

@ -1,198 +0,0 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.extension.api.command;
import de.jeremystartm.pickshadow.extension.ExtensionConfiguration;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.staropensource.engine.base.logging.Logger;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.craftbukkit.command.ServerCommandSender;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Abstract class for implementing commands.
*
* @since v1-release0
*/
@Getter
public abstract class CommandBase implements CommandExecutor {
/**
* Contains a list of all registered commands.
*
* @since v1-release0
*/
private static final @NotNull List<@NotNull CommandBase> REGISTERED = new ArrayList<>();
/**
* Contains a {@link CommandExecutor} implementation
* for disabled commands (caused by a disabled mode).
*
* @see ExtensionConfiguration#getEnabledModes()
* @since v1-release0
*/
public static final @NotNull CommandExecutor disallowedExecutor = (sender, command, alias, arguments) -> {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_INVALID_MODE, sender, true));
return true;
};
/**
* Contains a list of all {@link Command}s this
* command has been registered for.
*
* @since v1-release0
*/
private final @NotNull List<@NotNull PluginCommand> commands = new ArrayList<>();
/**
* Initializes this abstract class
* and registers the command.
*
* @param mode mode to register this command in
* @param commands all commands this class should handle
* @throws IllegalArgumentException if a command does not exist
* @since v1-release0
*/
public CommandBase(@NotNull String mode, @NotNull String... commands) throws IllegalArgumentException {
boolean disallowedByMode = !Arrays.stream(ExtensionConfiguration.getInstance().getEnabledModes()).toList().contains(mode);
for (String command : commands) {
PluginCommand pluginCommand = Bukkit.getPluginCommand(command);
if (pluginCommand == null)
throw new IllegalArgumentException("Command registration failed: The command \"" + command + "\" does not exist");
if (disallowedByMode) {
pluginCommand.setExecutor(disallowedExecutor);
pluginCommand.setTabCompleter(null);
} else {
pluginCommand.setExecutor(this);
pluginCommand.setTabCompleter(new TabCompleter() {
@Override
public @NotNull List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
return StringUtil.copyPartialMatches(args[args.length - 1], getCompletion().complete(sender, label, args), new ArrayList<>());
}
});
}
this.commands.add(pluginCommand);
}
REGISTERED.add(this);
}
/**
* Initializes this abstract class
* and registers the command.
* <p>
* Using this constructor instead of
* {@link #CommandBase(String, String...)}
* causes the creation of a dummy command
* which must be registered manually.
* Not recommended, use only when needed.
*
* @since v1-release0
*/
public CommandBase() {
REGISTERED.add(this);
}
/** {@inheritDoc} */
@Override
public final boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
try {
invoke(sender, command, alias, args);
} catch (Exception exception) {
Logger.crash(
"Command /"
+ command.getName()
+ " (under alias /"
+ alias
+ ") failed for sender "
+ sender.getName()
+ " (console="
+ (sender instanceof ConsoleCommandSender)
+ ") with the following arguments:\n"
+ Arrays.toString(args),
exception,
false);
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNKNOWN, sender, true));
}
return true;
}
/**
* Executes this command.
*
* @since v1-release0
*/
@SuppressWarnings("NullableProblems") // intentional, see CommandBaseWithNull
public abstract void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments);
/**
* Provides tab completions for this command.
*
* @return completion
* @since v1-release0
*/
public abstract @NotNull TabCompletion getCompletion();
/**
* Performs a permission check, sends the sender
* an error message and then returns.
* Useful for easy permission checks.
*
* @param sender sender to check
* @param permission permission to check for
* @return {@code true} if the permission is missing, {@code false} otherwise
* @since v1-release0
*/
protected static boolean checkPermission(@NotNull CommandSender sender, @NotNull String permission) {
if (sender instanceof ServerCommandSender)
return false;
if (!sender.hasPermission(permission)) {
sender.sendRichMessage(
TranslationManager.get(LanguageString.ERROR_MISSING_PERM, sender, true)
.replace("%permission%", permission)
);
return true;
}
return false;
}
/**
* Returns a list of all registered commands.
*
* @return list of registered commands
* @since v1-release0
*/
public static List<@NotNull CommandBase> getREGISTERED() {
return Collections.unmodifiableList(REGISTERED);
}
}

View file

@ -0,0 +1,83 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.extension.api.command;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer;
import lombok.Getter;
import org.bukkit.command.*;
import org.bukkit.craftbukkit.command.ServerCommandSender;
import org.jetbrains.annotations.NotNull;
/**
* Abstract class for implementing commands.
* <p>
* Forces {@link #invokeAll(CommandSender, String, String[])},
* {@link #invokeConsole(ServerCommandSender, String, String[])}
* and {@link #invokePlayer(PSPlayer, String, String[])}
* on the implementation class.
* <p>
* Very useful during development.
*
* @see Command
* @since v1-release0
*/
@Getter
public abstract class CommandForced extends Command {
/**
* Initializes this abstract class
* and registers the command.
*
* @param information information about the command
* @param commands all commands this class should handle
* @throws IllegalArgumentException if a command does not exist
* @since v1-release0
*/
public CommandForced(@NotNull Command.Information information, @NotNull String... commands) throws IllegalArgumentException {
super(information, commands);
}
/**
* Initializes this abstract class
* and registers the command.
* <p>
* Using this constructor instead of
* {@link #CommandForced(Information, String...)}
* causes the creation of a dummy command
* which must be registered manually.
* Not recommended, use only when needed.
*
* @since v1-release0
*/
public CommandForced(@NotNull Command.Information information) {
super(information);
}
/** {@inheritDoc} */
@Override
protected abstract void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) throws Exception;
/** {@inheritDoc} */
@Override
protected abstract void invokeConsole(@NotNull ServerCommandSender console, @NotNull String alias, @NotNull String[] arguments) throws Exception;
/** {@inheritDoc} */
@Override
protected abstract void invokePlayer(@NotNull PSPlayer player, @NotNull String alias, @NotNull String[] arguments) throws Exception;
}

View file

@ -0,0 +1,129 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.extension.api.entity.player;
import de.staropensource.engine.base.logging.Logger;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* A factory for {@link PSPlayer} instances.
*
* @since v1-release0
*/
public final class PSPlayerFactory {
/**
* Contains all registered {@link PSPlayer.Data} instances.
*
* @since v1-release0
*/
private static final @NotNull List<@NotNull PSPlayer> instances = new ArrayList<>();
/**
* Creates and initializes an instance of this class.
*
* @since v1-release0
*/
private PSPlayerFactory() {}
/**
* Returns an already existing {@link PSPlayer.Data} instance.
*
* @param uuid player {@link UUID}
* @return {@link PSPlayer} instance
* @throws NullPointerException on error
* @since v1-release0
*/
public static @NotNull PSPlayer get(@NotNull UUID uuid) throws NullPointerException {
for (PSPlayer player : instances)
if (player.getUUID() == uuid)
return player;
throw new NullPointerException();
}
/**
* Returns an already existing {@link PSPlayer.Data} instance.
*
* @param username player username
* @return {@link PSPlayer} instance
* @throws NullPointerException on error
* @since v1-release0
*/
public static PSPlayer get(@NotNull String username) throws NullPointerException {
for (PSPlayer player : instances)
if (player.getUsername().equals(username))
return player;
throw new NullPointerException();
}
/**
* Returns an already existing {@link PSPlayer.Data} instance.
*
* @param bukkitPlayer Bukkit's {@link Player} instance
* @return {@link PSPlayer} instance
* @throws NullPointerException on error
* @since v1-release0
*/
public static @NotNull PSPlayer get(@NotNull Player bukkitPlayer) throws NullPointerException {
for (PSPlayer player : instances)
if (player.getUUID() == bukkitPlayer.getUniqueId())
return player;
throw new NullPointerException();
}
/**
* Registers a new {@link PSPlayer.Data} instance.
*
* @param bukkitPlayer Bukkit's {@link Player} instance
* @throws Exception on error
* @since v1-release0
*/
public static @NotNull PSPlayer registerPlayer(@NotNull Player bukkitPlayer) throws Exception {
Logger.verb("Registering player " + bukkitPlayer.getName() + " [" + bukkitPlayer.getUniqueId() + "]");
try {
PSPlayer player = new PSPlayer(bukkitPlayer);
instances.add(player);
return player;
} catch (Exception exception) {
Logger.crash("Unable to create PlayerData instance for player " + bukkitPlayer.getName() + " [" + bukkitPlayer.getUniqueId() + "]", exception, true);
throw exception;
}
}
/**
* Unregisters a {@link PSPlayer.Data} instance.
*
* @param player {@link PSPlayer} instance
* @since v1-release0
*/
public static void unregisterPlayer(@NotNull PSPlayer player) {
Logger.verb("Unregistering player " + player.getUsername() + " [" + player.getUUID() + "]");
instances.remove(player);
}
}

View file

@ -1,258 +0,0 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.extension.api.entity.player;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import de.jeremystartm.pickshadow.extension.misc.Scheduler;
import de.staropensource.engine.base.logging.Logger;
import fr.mrmicky.fastboard.adventure.FastBoard;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.UUID;
import static java.util.Map.entry;
@Setter
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class PlayerData {
/**
* Contains the associated {@link Player}.
* <p>
* <b>Will be saved.</b>
*
* @since v1-release0
* -- GETTER --
* Returns the associated {@link Player}.
* <p>
* <b>Will be saved.</b>
*
* @return associated {@link Player}
* @since v1-release0
*/
@Setter(value = AccessLevel.NONE)
private final Player player;
/**
* Contains the player list scoreboard.
* <p>
* <b>Will not be saved.</b>
*
* @since v1-release0
* -- GETTER --
* Returns the player list scoreboard.
* <p>
* <b>Will not be saved.</b>
*
* @return player list scoreboard
* @since v1-release0
* -- SETTER --
* Sets the player list scoreboard.
* <p>
* <b>Will not be saved.</b>
*
* @param playerListScoreboard new player list scoreboard
* @since v1-release0
*/
@ApiStatus.Experimental
private @NotNull FastBoard playerListScoreboard;
/**
* Contains the preferred language
* the player has set.
* <p>
* <b>Will be saved.</b>
*
* @since v1-release0
* -- GETTER --
* Returns the preferred language
* the player has set.
* <p>
* <b>Will be saved.</b>
*
* @return preferred language
* @since v1-release0
* -- SETTER --
* Sets the preferred language
* the player has set.
* <p>
* <b>Will be saved.</b>
*
* @param language new preferred language
* @since v1-release0
*/
private String language;
/**
* Contains when the player has
* first been seen on the server.
* <p>
* <b>Will be saved.</b>
*
* @since v1-release0
* -- GETTER --
* Returns when the player has
* first been seen on the server.
* <p>
* <b>Will be saved.</b>
*
* @return first played date and time
* @since v1-release0
*/
private ZonedDateTime firstSeen;
/**
* Contains the UUID of the player
* this player has messaged last.
* <p>
* <b>Will be saved.</b>
*
* @since v1-release0
* -- GETTER --
* Returns the UUID of the player
* this player has messaged last.
* <p>
* <b>Will be saved.</b>
*
* @return UUID of the player last messaged
* @since v1-release0
*/
private UUID lastMessaged;
/**
* Contains the state for
* stone cutter damage, as
* assigned by the {@link Scheduler}.
* <p>
* <b>Will not be saved.</b>
*
* @since v1-release0
* -- GETTER --
* Returns the state for
* stone cutter damage, as
* assigned by the {@link Scheduler}.
* <p>
* <b>Will not be saved.</b>
*
* @return stone cutter damage state
* @since v1-release0
*/
private int stonecutterDamageState = -1;
/**
* Creates and initializes an instance of this class.
* <p>
* This constructor creates a completely
* new instance without any data.
*
* @param player {@link Player} to use
* @since v1-release0
*/
PlayerData(@NotNull Player player) {
Logger.info("Initializing fresh player data for player " + player.getName() + " [" + player.getUniqueId() + "]");
this.player = player;
//TabListHandler.getInstance().initializeTabList(this);
language = "en";
firstSeen = ZonedDateTime.now();
lastMessaged = null;
}
/**
* Creates and initializes an instance of this class.
* <p>
* This constructor creates a new instance
* from already existing player data.
*
* @param player {@link Player} to use
* @param firstSeen when the player was first seen
* @since v1-release0
*/
private PlayerData(@NotNull Player player, @NotNull String language, @NotNull ZonedDateTime firstSeen, @Nullable UUID lastMessaged) {
Logger.info("Initializing player data from existing data for player " + player.getName() + " [" + player.getUniqueId() + "]");
this.player = player;
//TabListHandler.getInstance().initializeTabList(this);
this.language = language;
this.firstSeen = firstSeen;
this.lastMessaged = lastMessaged;
}
/**
* Deserializes a JSON object and creates
* a new {@link PlayerData} instance.
*
* @param jsonString JSON string
* @throws JsonSyntaxException on invalid JSON
* @throws RuntimeException on invalid PlayerData serialization
* @since v1-release0
*/
public static @NotNull PlayerData fromJSON(@NotNull String jsonString) throws JsonSyntaxException, NullPointerException {
try {
Map<@NotNull String, @NotNull String> data = new Gson().fromJson(jsonString, new TypeToken<Map<@NotNull String, @NotNull String>>() {
}.getType());
Player player = Bukkit.getPlayer(UUID.fromString(data.get("playerUUID")));
if (player == null)
throw new NullPointerException("Player is null");
return new PlayerData(
player,
data.get("language"),
ZonedDateTime.parse(data.get("firstPlayed")),
data.get("lastMessaged").isBlank() ? null : UUID.fromString(data.get("lastMessaged"))
);
} catch (Exception exception) {
if (exception instanceof JsonSyntaxException)
throw exception;
else
throw new RuntimeException("A conversion method failed", exception);
}
}
/**
* Serializes this instance into a JSON object.
*
* @return serialized {@link PlayerData} instance in JSON
* @since v1-release0
*/
public @NotNull String toJSON() {
return new Gson().toJson(
Map.ofEntries(
entry("playerUUID", player.getUniqueId().toString()),
entry("language", language),
entry("firstPlayed", firstSeen.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)),
entry("lastMessaged", lastMessaged == null ? "" : lastMessaged.toString())
),
new TypeToken<Map<@NotNull String, @NotNull String>>(){}.getType());
}
}

View file

@ -1,153 +0,0 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.extension.api.entity.player;
import de.staropensource.engine.base.logging.Logger;
import lombok.Getter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* A factory for {@link PlayerData} instances.
*
* @since v1-release0
*/
@SuppressWarnings({ "JavadocDeclaration" })
public final class PlayerDataFactory {
/**
* Contains the global instance of this class.
*
* @since v1-release0
* -- GETTER --
* Returns the global instance of this class.
*
* @return global instance
* @since v1-release0
*/
@Getter
private static PlayerDataFactory instance;
/**
* Contains all registered {@link PlayerData} instances.
*
* @since v1-release0
*/
private final @NotNull List<@NotNull PlayerData> playerList = new ArrayList<>();
/**
* Creates and initializes an instance of this class.
*
* @since v1-release0
*/
private PlayerDataFactory() {}
/**
* Initializes this factory,
* if it isn't already.
*
* @since v1-release0
*/
public static void initialize() {
if (instance == null)
instance = new PlayerDataFactory();
}
/**
* Returns an already existing {@link PlayerData} instance.
*
* @param uuid player {@link UUID}
* @return {@link PlayerData} instance
* @throws NullPointerException on error
* @since v1-release0
*/
public PlayerData get(@NotNull UUID uuid) throws NullPointerException {
for (PlayerData playerData : playerList)
if (playerData.getPlayer().getUniqueId() == uuid)
return playerData;
throw new NullPointerException();
}
/**
* Returns an already existing {@link PlayerData} instance.
*
* @param username player username
* @return {@link PlayerData} instance
* @throws NullPointerException on error
* @since v1-release0
*/
public PlayerData get(@NotNull String username) throws NullPointerException {
for (PlayerData playerData : playerList)
if (playerData.getPlayer().getName().equals(username))
return playerData;
throw new NullPointerException();
}
/**
* Returns an already existing {@link PlayerData} instance.
*
* @param player {@link Player} instance
* @return player instance
* @throws NullPointerException on error
* @since v1-release0
*/
public @NotNull PlayerData get(@NotNull Player player) throws NullPointerException {
for (PlayerData playerData : playerList)
if (playerData.getPlayer().getUniqueId() == player.getUniqueId())
return playerData;
throw new NullPointerException();
}
/**
* Registers a new {@link PlayerData} instance.
*
* @param player {@link Player} instance
* @throws Exception on error
* @since v1-release0
*/
public void registerPlayer(@NotNull Player player) throws Exception {
Logger.verb("Registering player " + player.getName() + " (" + player.getUniqueId() + ")");
try {
playerList.add(new PlayerData(player));
} catch (Exception exception) {
Logger.crash("Unable to create PlayerData instance for player " + player.getName() + " (" + player.getUniqueId() + ")", exception, true);
throw exception;
}
}
/**
* Unregisters a {@link PlayerData} instance.
*
* @param playerData {@link Player} instance
* @since v1-release0
*/
public void unregisterPlayer(@NotNull PlayerData playerData) {
Logger.verb("Unregistering player " + playerData.getPlayer().getName() + " (" + playerData.getPlayer().getUniqueId() + ")");
playerList.remove(playerData);
}
}

View file

@ -45,6 +45,7 @@ public enum LanguageString {
ERROR_UNIMPLEMENTED, ERROR_UNIMPLEMENTED,
ERROR_INVALID_MODE, ERROR_INVALID_MODE,
ERROR_NOT_A_PLAYER, ERROR_NOT_A_PLAYER,
ERROR_NOT_SERVER_CONSOLE,
ERROR_MISSING_PERM, ERROR_MISSING_PERM,
ERROR_TOO_FEW_ARGUMENTS, ERROR_TOO_FEW_ARGUMENTS,
ERROR_TOO_MANY_ARGUMENTS, ERROR_TOO_MANY_ARGUMENTS,
@ -64,7 +65,9 @@ public enum LanguageString {
EXTENSIONCMD_KILLJVM, EXTENSIONCMD_KILLJVM,
EXTENSIONCMD_LICENSE, EXTENSIONCMD_LICENSE,
EXTENSIONCMD_SOURCE, EXTENSIONCMD_SOURCE,
EXTENSIONCMD_ERROR_OLDCMD,
// Command /pssp
LEGACYEXTENSIONCMD,
// Command group 'messaging' // Command group 'messaging'
MESSAGING_SERVER, MESSAGING_SERVER,
@ -114,6 +117,10 @@ public enum LanguageString {
HEAL, HEAL,
HEAL_REMOTE, HEAL_REMOTE,
// Command /feed
FEED,
FEED_REMOTE,
// Command /plugins // Command /plugins
PLUGINS, PLUGINS,
PLUGINS_FAKE, PLUGINS_FAKE,
@ -133,6 +140,12 @@ public enum LanguageString {
GAMEMODE_ADVENTURE, GAMEMODE_ADVENTURE,
GAMEMODE_SPECTATOR, GAMEMODE_SPECTATOR,
// Command /speed
SPEED,
SPEED_REMOTE,
SPEED_FLY,
SPEED_WALK,
// Event for chat commands // Event for chat commands
CHATCOMMAND_ERROR_NAMESPACE, CHATCOMMAND_ERROR_NAMESPACE,
} }

View file

@ -22,7 +22,8 @@ package de.jeremystartm.pickshadow.extension.api.translation;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory; import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayerFactory;
import de.staropensource.engine.base.logging.Logger; import de.staropensource.engine.base.logging.Logger;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -60,6 +61,40 @@ public final class TranslationManager {
return translations.keySet().toArray(new String[0]); return translations.keySet().toArray(new String[0]);
} }
/**
* Returns the translation for the specified language
* string for the specified {@link CommandSender}.
*
* @param languageString language string to get
* @param player player to translate for
* @param includePrefix if {@link LanguageString#PREFIX} should be prepended
* @param placeholders placeholders
* @since v1-release0
*/
@SafeVarargs
public static @NotNull String get(
@NotNull LanguageString languageString,
@NotNull PSPlayer player,
boolean includePrefix,
@NotNull Map.Entry<@NotNull String, @NotNull String> @Nullable ... placeholders
) {
String temp = player.getData().getLanguage();
// Check if the prefix shall be included
if (includePrefix)
temp = get(LanguageString.PREFIX, "en") + get(languageString, temp).replace("\n", "\n" + get(LanguageString.PREFIX_NEWLINE, "en"));
else
temp = get(languageString, temp);
// Replace placeholders
if (placeholders != null)
for (Map.Entry<@NotNull String, @NotNull String> placeholder : placeholders)
temp = temp.replace("%" + placeholder.getKey() + "%", placeholder.getValue());
// Return
return temp;
}
/** /**
* Returns the translation for the specified language * Returns the translation for the specified language
* string for the specified {@link CommandSender}. * string for the specified {@link CommandSender}.
@ -71,13 +106,18 @@ public final class TranslationManager {
* @since v1-release0 * @since v1-release0
*/ */
@SafeVarargs @SafeVarargs
public static @NotNull String get(@NotNull LanguageString languageString, @NotNull CommandSender sender, boolean includePrefix, @NotNull Map.Entry<@NotNull String, @NotNull String> @Nullable ... placeholders) { public static @NotNull String get(
@NotNull LanguageString languageString,
@NotNull CommandSender sender,
boolean includePrefix,
@NotNull Map.Entry<@NotNull String, @NotNull String> @Nullable ... placeholders
) {
String temp = "en"; String temp = "en";
// Determine language to use // Determine language to use
if (sender instanceof Player player) if (sender instanceof Player player)
try { try {
temp = PlayerDataFactory.getInstance().get(player).getLanguage(); temp = PSPlayerFactory.get(player).getData().getLanguage();
} catch (NullPointerException ignored) {} } catch (NullPointerException ignored) {}
// Check if the prefix shall be included // Check if the prefix shall be included

View file

@ -17,44 +17,56 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package de.jeremystartm.pickshadow.extension.api.command; package de.jeremystartm.pickshadow.extension.api.type;
import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion;
import lombok.Getter;
import org.bukkit.command.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Abstract class for implementing commands * Represents various attributes players can have.
* without the {@code command} parameter.
* *
* @since v1-release0 * @since v1-release0
*/ */
@Getter public enum PlayerAttribute {
public abstract class CommandBaseWithNull extends CommandBase {
/** /**
* Initializes this abstract class * A player's walking speed.
* and registers the command. * <p>
* Must be a {@link Float}.
* *
* @since v1-release0 * @since v1-release0
*/ */
public CommandBaseWithNull() {} WALKING_SPEED,
/** /**
* Executes this command. * A player's flying speed.
* <p>
* Must be a {@link Float}.
* *
* @since v1-release0 * @since v1-release0
*/ */
public abstract void invoke(@NotNull CommandSender sender, @Nullable Command command, @NotNull String alias, @NotNull String[] arguments); FLY_SPEED;
/** /**
* Provides tab completions for this command. * Returns the default value for the specified attribute.
* *
* @return completion * @return default value
* @since v1-release0 * @since v1-release0
*/ */
public @NotNull TabCompletion getCompletion() { public @NotNull Object getDefault() {
return StubTabCompletion.completion(); return switch (this) {
case WALKING_SPEED -> 0.2f;
case FLY_SPEED -> 0.1f;
};
}
/**
* Returns the zero value for the specified attribute.
*
* @return {@code 0}
* @since v1-release0
*/
public @NotNull Object getZero() {
return switch (this) {
case WALKING_SPEED, FLY_SPEED -> 0f;
};
} }
} }

View file

@ -0,0 +1,46 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.extension.api.type;
/**
* Represents damage states of players.
*
* @since v1-release0
*/
public enum PlayerDamageState {
/**
* For stonecutter damage detection.
*
* @since v1-release0
*/
STONECUTTER;
/**
* Returns the default value for the specified damage state.
*
* @return default value
* @since v1-release0
*/
public int getDefault() {
return switch (this) {
case STONECUTTER -> -1;
};
}
}

View file

@ -0,0 +1,25 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Data types in form of enums and classes.
*
* @since v1-release0
*/
package de.jeremystartm.pickshadow.extension.api.type;

View file

@ -19,14 +19,15 @@
package de.jeremystartm.pickshadow.extension.command; package de.jeremystartm.pickshadow.extension.command;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.CommandForced;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.command.ServerCommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
@ -36,7 +37,7 @@ import org.jetbrains.annotations.NotNull;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class TemplateCommand extends CommandBase { public final class TemplateCommand extends CommandForced {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -61,14 +62,40 @@ public final class TemplateCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public TemplateCommand() throws IllegalArgumentException { public TemplateCommand() throws IllegalArgumentException {
super("mode", "cmd"); super(new Information(
"name",
new String[]{ "alias 1", "alias 2" },
"An example command",
"/cmd [--verbose] <arg1|arg2|arg3>",
"mode",
null,
ExecutionTarget.ALL
), "cmd");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { public void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.cmd")) return; if (checkPermission(sender, "pickshadow.command.cmd")) return;
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true)); sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true));
} }
/** {@inheritDoc} */
@Override
public void invokeConsole(@NotNull ServerCommandSender console, @NotNull String alias, @NotNull String[] arguments) {
// No permission check is performed here
// here as the server console will
// always have all permission set.
console.sendPlainMessage("This command seems to have been invoked by the server console");
}
/** {@inheritDoc} */
@Override
public void invokePlayer(@NotNull PSPlayer player, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(player, "pickshadow.command.cmd")) return;
player.messageRaw("This command seems to have been invoked by a player");
}
} }

View file

@ -19,7 +19,7 @@
package de.jeremystartm.pickshadow.extension.command.general; package de.jeremystartm.pickshadow.extension.command.general;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
@ -28,7 +28,6 @@ import de.staropensource.engine.base.utility.PlaceholderEngine;
import lombok.Getter; import lombok.Getter;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -39,7 +38,7 @@ import org.jetbrains.annotations.NotNull;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class AnnounceCommand extends CommandBase { public final class AnnounceCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -61,12 +60,20 @@ public final class AnnounceCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public AnnounceCommand() throws IllegalArgumentException { public AnnounceCommand() throws IllegalArgumentException {
super("general", "announce"); super(new Information(
"announce",
new String[]{ "announce", "announcement", "broadcast", "bc" },
"",
"",
"general",
null,
ExecutionTarget.ALL
), "announce");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) throws Exception {
if (checkPermission(sender, "pickshadow.command.announce")) return; if (checkPermission(sender, "pickshadow.command.announce")) return;
if (arguments.length == 0) { if (arguments.length == 0) {
@ -106,6 +113,8 @@ public final class AnnounceCommand extends CommandBase {
if (!checkPermission(sender, "pickshadow.command.announce.network")) if (!checkPermission(sender, "pickshadow.command.announce.network"))
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true)); sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true));
} else } else
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(PlaceholderEngine.getInstance().process(argumentsFinalized))); // TODO broken
//Bukkit.broadcast(MiniMessage.miniMessage().deserialize(PlaceholderEngine.getInstance().process(argumentsFinalized)));
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(argumentsFinalized));
} }
} }

View file

@ -19,14 +19,13 @@
package de.jeremystartm.pickshadow.extension.command.general; package de.jeremystartm.pickshadow.extension.command.general;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -40,7 +39,7 @@ import static java.util.Map.entry;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class ClearChatCommand extends CommandBase { public final class ClearChatCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -68,12 +67,20 @@ public final class ClearChatCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public ClearChatCommand() throws IllegalArgumentException { public ClearChatCommand() throws IllegalArgumentException {
super("general", "clearchat"); super(new Information(
"clearchat",
new String[]{ "clearchat", "chatclear", "cc" },
"",
"",
"general",
null,
ExecutionTarget.ALL
), "clearchat");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) throws Exception {
if (checkPermission(sender, "pickshadow.command.clearchat")) return; if (checkPermission(sender, "pickshadow.command.clearchat")) return;
if (arguments.length == 1 && arguments[0].equals("--network")) { if (arguments.length == 1 && arguments[0].equals("--network")) {

View file

@ -19,15 +19,17 @@
package de.jeremystartm.pickshadow.extension.command.general; package de.jeremystartm.pickshadow.extension.command.general;
import com.google.gson.Gson;
import de.jeremystartm.pickshadow.common.PSSKInformation; import de.jeremystartm.pickshadow.common.PSSKInformation;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory; import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayerFactory;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.jeremystartm.pickshadow.extension.api.type.PlayerAttribute;
import de.staropensource.engine.base.utility.PlaceholderEngine;
import lombok.Getter; import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -41,7 +43,7 @@ import static java.util.Map.entry;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class ExtensionCommand extends CommandBase { public final class ExtensionCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -53,12 +55,10 @@ public final class ExtensionCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
private final @NotNull TabCompletion completion = new StaticTabCompletion() private final @NotNull TabCompletion completion = new StaticTabCompletion()
.add("psse", 0, "license", "pickshadow.command.extension") .add("", 0, "license", "pickshadow.command.extension")
.add("psse", 0, "source", "pickshadow.command.extension") .add("", 0, "source", "pickshadow.command.extension")
.add("psse", 0, "killjvm", "pickshadow.command.extension.advanced") .add("", 0, "killjvm", "pickshadow.command.extension.advanced")
.add("psse", 0, "debug", "pickshadow.command.extension.advanced") .add("", 0, "debug", "pickshadow.command.extension.advanced");
.copy("psse", "pickshadow")
.copy("psse", "server");
/** /**
* Creates and initializes an instance of * Creates and initializes an instance of
@ -67,14 +67,20 @@ public final class ExtensionCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public ExtensionCommand() throws IllegalArgumentException { public ExtensionCommand() throws IllegalArgumentException {
super("general", "psse", "pssp"); super(new Information(
"pssp",
new String[]{ "psse", "pickshadow", "server", "about", "version", "ver" },
"",
"",
"general",
null,
ExecutionTarget.ALL
), "psse");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) throws Exception {
switch (alias) {
case "psse", "pickshadow", "server" -> {
if (checkPermission(sender, "pickshadow.command.extension")) return; if (checkPermission(sender, "pickshadow.command.extension")) return;
if (arguments.length == 0) if (arguments.length == 0)
@ -110,9 +116,15 @@ public final class ExtensionCommand extends CommandBase {
case "debug" -> { case "debug" -> {
if (checkPermission(sender, "pickshadow.command.extension.advanced")) return; if (checkPermission(sender, "pickshadow.command.extension.advanced")) return;
if (sender instanceof Player player) if (sender instanceof Player player) {
sender.sendMessage(PlayerDataFactory.getInstance().get(player).toJSON()); if (PlaceholderEngine.getInstance() == null) {
else PlaceholderEngine.initialize();
sender.sendMessage("Initialized the PlaceholderEngine");
}
// Send serialized player data
sender.sendMessage(PSPlayerFactory.get(player).getData().toJSON());
} else
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true)); sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true));
} }
default -> sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_INVALID_ARGUMENT, sender, true, entry("argument", arguments[0]))); default -> sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_INVALID_ARGUMENT, sender, true, entry("argument", arguments[0])));
@ -121,10 +133,4 @@ public final class ExtensionCommand extends CommandBase {
Runtime.getRuntime().halt(0); Runtime.getRuntime().halt(0);
} }
} }
case "pssp" -> {
if (!checkPermission(sender, "pickshadow.command.extension.legacy"))
sender.sendRichMessage(TranslationManager.get(LanguageString.EXTENSIONCMD_ERROR_OLDCMD, sender, true));
}
}
}
} }

View file

@ -19,14 +19,13 @@
package de.jeremystartm.pickshadow.extension.command.general; package de.jeremystartm.pickshadow.extension.command.general;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory; import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayerFactory;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -42,7 +41,7 @@ import static java.util.Map.entry;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class LanguageCommand extends CommandBase { public final class LanguageCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -62,7 +61,15 @@ public final class LanguageCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public LanguageCommand() throws IllegalArgumentException { public LanguageCommand() throws IllegalArgumentException {
super("general", "language"); super(new Information(
"language",
new String[]{ "language", "lang", "setlanguage", "setlang" },
"",
"",
"general",
null,
ExecutionTarget.PLAYERS_ONLY
), "language");
// Initialize completion // Initialize completion
StaticTabCompletion staticTabCompletion = new StaticTabCompletion(); StaticTabCompletion staticTabCompletion = new StaticTabCompletion();
@ -79,7 +86,7 @@ public final class LanguageCommand extends CommandBase {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) throws Exception {
if (checkPermission(sender, "pickshadow.command.language")) return; if (checkPermission(sender, "pickshadow.command.language")) return;
if (sender instanceof Player player) { if (sender instanceof Player player) {
@ -89,7 +96,7 @@ public final class LanguageCommand extends CommandBase {
LanguageString.LANGUAGE_CURRENT, LanguageString.LANGUAGE_CURRENT,
sender, sender,
true, true,
entry("language", PlayerDataFactory.getInstance().get(player).getLanguage()) entry("language", PSPlayerFactory.get(player).getData().getLanguage())
)); ));
else if (arguments.length == 1) {// Check if language is loaded else if (arguments.length == 1) {// Check if language is loaded
if (!Arrays.asList(TranslationManager.getLanguages()).contains(arguments[0])) { if (!Arrays.asList(TranslationManager.getLanguages()).contains(arguments[0])) {
@ -102,7 +109,7 @@ public final class LanguageCommand extends CommandBase {
} }
// Change language // Change language
PlayerDataFactory.getInstance().get(player).setLanguage(arguments[0]); PSPlayerFactory.get(player).getData().setLanguage(arguments[0]);
// Send success message // Send success message
sender.sendRichMessage(TranslationManager.get( sender.sendRichMessage(TranslationManager.get(

View file

@ -0,0 +1,75 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.extension.command.general;
import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
/**
* Handles the {@code /pssp} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class LegacyExtensionCommand extends Command {
/**
* Contains the tab completion for this command.
*
* @since v1-release0
* -- GETTER --
* Returns the tab completion for this command.
*
* @return tab completion
* @since v1-release0
*/
private final @NotNull TabCompletion completion = StubTabCompletion.completion();
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public LegacyExtensionCommand() throws IllegalArgumentException {
super(new Command.Information(
"pssp",
new String[]{ "pssp" },
"",
"/pssp",
"general",
null,
ExecutionTarget.PLAYERS_ONLY
), "pssp");
}
/** {@inheritDoc} */
@Override
public void invokePlayer(@NotNull PSPlayer player, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(player, "pickshadow.command.extension.legacy")) return;
player.messageTranslatable(LanguageString.LEGACYEXTENSIONCMD, true);
}
}

View file

@ -19,13 +19,12 @@
package de.jeremystartm.pickshadow.extension.command.general; package de.jeremystartm.pickshadow.extension.command.general;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -36,7 +35,7 @@ import org.jetbrains.annotations.NotNull;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class LinkCommand extends CommandBase { public final class LinkCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -56,12 +55,20 @@ public final class LinkCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public LinkCommand() throws IllegalArgumentException { public LinkCommand() throws IllegalArgumentException {
super("general", "website", "forum", "discord", "teamspeak", "mumble"); super(new Information(
"link",
new String[]{ "website", "forum", "discord", "teamspeak", "mumble" },
"",
"",
"general",
null,
ExecutionTarget.ALL
), "website", "forum", "discord", "teamspeak", "mumble");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.link")) return; if (checkPermission(sender, "pickshadow.command.link")) return;
switch (alias) { switch (alias) {

View file

@ -0,0 +1,227 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.extension.command.general;
import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayerFactory;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.jeremystartm.pickshadow.extension.api.type.PlayerAttribute;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import static java.util.Map.entry;
/**
* Handles the {@code /speed} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class SpeedCommand extends Command {
/**
* Contains the tab completion for this command.
*
* @since v1-release0
* -- GETTER --
* Returns the tab completion for this command.
*
* @return tab completion
* @since v1-release0
*/
private final @NotNull TabCompletion completion = new StaticTabCompletion()
.add("speed", 0, "walk", "pickshadow.command.speed.walk")
.add("speed", 0, "fly", "pickshadow.command.speed.fly")
.add("speed", 1, "default", "pickshadow.command.speed")
.add("speed", 1, "0", "pickshadow.command.speed")
.add("speed", 1, "0.1", "pickshadow.command.speed")
.add("speed", 1, "0.2", "pickshadow.command.speed")
.add("speed", 1, "0.25", "pickshadow.command.speed")
.add("speed", 1, "0.3", "pickshadow.command.speed")
.add("speed", 1, "0.5", "pickshadow.command.speed")
.add("speed", 1, "0.5", "pickshadow.command.speed")
.add("speed", 1, "0.6", "pickshadow.command.speed")
.add("speed", 1, "0.7", "pickshadow.command.speed")
.add("speed", 1, "0.75", "pickshadow.command.speed")
.add("speed", 1, "0.8", "pickshadow.command.speed")
.add("speed", 1, "0.9", "pickshadow.command.speed")
.add("speed", 1, "1", "pickshadow.command.speed")
.players("speed", 2);
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public SpeedCommand() throws IllegalArgumentException {
super(new Information(
"speed",
new String[]{ "speed" },
"",
"",
"general",
null,
ExecutionTarget.CONSOLE_PARTIAL
), "speed");
}
/** {@inheritDoc} */
@Override
protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.speed")) return;
// Check length of 'arguments'
if (arguments.length < 2) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_FEW_ARGUMENTS, sender, true));
return;
} else if (arguments.length > 3) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true));
return;
}
boolean onSelf;
PSPlayer target;
float speed;
boolean mode;
// Determine 'mode'
switch (arguments[0]) {
case "fly" -> {
if (checkPermission(sender, "pickshadow.command.speed.fly"))
return;
else
mode = true;
}
case "walk" -> {
if (checkPermission(sender, "pickshadow.command.speed.walk"))
return;
else
mode = false;
}
default -> {
sender.sendRichMessage(TranslationManager.get(
LanguageString.ERROR_INVALID_ARGUMENT,
sender,
true,
entry("argument", arguments[0])
));
return;
}
}
// Determine 'speed'
if (arguments[1].equals("default"))
if (mode)
speed = 0.1f;
else
speed = 0.2f;
else
speed = Float.parseFloat(arguments[1]);
// Cap 'speed'
if (speed > 1f)
speed = 1f;
if (speed < 0f)
speed = 0f;
// Get player/'target'
switch (arguments.length) {
case 2 -> {
onSelf = true;
// Check if command sender is a player
if (sender instanceof Player senderPlayer)
target = PSPlayerFactory.get(senderPlayer);
else {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true));
return;
}
}
case 3 -> {
Player bukkitPlayer = Bukkit.getPlayer(arguments[2]);
// Check if 'bukkitPlayer' is null
if (bukkitPlayer == null) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_PLAYER_NOT_FOUND,
sender,
true,
entry("player", arguments[2])
));
return;
}
// Set 'onSelf'
try {
onSelf = bukkitPlayer.getName().equals(sender.getName());
} catch (NullPointerException exception) {
onSelf = false;
}
// Set 'target'
target = PSPlayerFactory.get(bukkitPlayer);
}
default -> {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true));
return;
}
}
// Set speed
try {
if (mode)
target.getData().setPlayerAttribute(PlayerAttribute.FLY_SPEED, speed);
else
target.getData().setPlayerAttribute(PlayerAttribute.WALKING_SPEED, speed);
} catch (IllegalArgumentException exception) {
sender.sendRichMessage(TranslationManager.get(
LanguageString.ERROR_INVALID_ARGUMENT,
sender,
true,
entry("argument", arguments[1])
));
return;
}
// Send message
target.messageTranslatable(
LanguageString.SPEED,
true,
entry("mode", TranslationManager.get(mode ? LanguageString.SPEED_FLY : LanguageString.SPEED_WALK, sender, false)),
entry("speed", String.valueOf(speed))
);
if (!onSelf)
sender.sendRichMessage(TranslationManager.get(
LanguageString.SPEED_REMOTE,
sender,
true,
entry("player", target.getUsername()),
entry("mode", TranslationManager.get(mode ? LanguageString.SPEED_FLY : LanguageString.SPEED_WALK, sender, false)),
entry("speed", String.valueOf(speed))
));
}
}

View file

@ -20,7 +20,7 @@
package de.jeremystartm.pickshadow.extension.command.general; package de.jeremystartm.pickshadow.extension.command.general;
import de.jeremystartm.pickshadow.extension.Extension; import de.jeremystartm.pickshadow.extension.Extension;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
@ -34,7 +34,6 @@ import net.kyori.adventure.title.Title;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Particle; import org.bukkit.Particle;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -50,7 +49,7 @@ import static java.util.Map.entry;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class TrollCommand extends CommandBase { public final class TrollCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -78,12 +77,20 @@ public final class TrollCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public TrollCommand() throws IllegalArgumentException { public TrollCommand() throws IllegalArgumentException {
super("general", "troll"); super(new Information(
"troll",
new String[]{ "troll" },
"",
"",
"general",
null,
ExecutionTarget.ALL
), "troll");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.troll")) if (checkPermission(sender, "pickshadow.command.troll"))
return; return;

View file

@ -19,7 +19,7 @@
package de.jeremystartm.pickshadow.extension.command.general.replacement; package de.jeremystartm.pickshadow.extension.command.general.replacement;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
@ -27,7 +27,6 @@ import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -37,13 +36,13 @@ import java.util.Objects;
import static java.util.Map.entry; import static java.util.Map.entry;
/** /**
* Handles the {@code /cmd} command. * Handles the {@code /gamemode} command.
* *
* @since v1-release0 * @since v1-release0
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class GamemodeCommand extends CommandBase { public final class GamemodeCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -73,12 +72,20 @@ public final class GamemodeCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public GamemodeCommand() throws IllegalArgumentException { public GamemodeCommand() throws IllegalArgumentException {
super("general", "gamemode"); super(new Information(
"gamemode",
new String[]{ "gamemode", "gm" },
"",
"",
"general",
null,
ExecutionTarget.CONSOLE_PARTIAL
), "gamemode");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) throws Exception {
if (checkPermission(sender, "pickshadow.command.gamemode")) return; if (checkPermission(sender, "pickshadow.command.gamemode")) return;
// Check length of 'arguments' // Check length of 'arguments'

View file

@ -19,13 +19,12 @@
package de.jeremystartm.pickshadow.extension.command.general.replacement; package de.jeremystartm.pickshadow.extension.command.general.replacement;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -36,7 +35,7 @@ import org.jetbrains.annotations.NotNull;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class HelpCommand extends CommandBase { public final class HelpCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -56,12 +55,20 @@ public final class HelpCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public HelpCommand() throws IllegalArgumentException { public HelpCommand() throws IllegalArgumentException {
super("general", "help"); super(new Information(
"help",
new String[]{ "help", "?" },
"",
"",
"general",
null,
ExecutionTarget.ALL
), "help");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) throws Exception {
if (checkPermission(sender, "pickshadow.command.help")) return; if (checkPermission(sender, "pickshadow.command.help")) return;
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true)); sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true));

View file

@ -19,15 +19,14 @@
package de.jeremystartm.pickshadow.extension.command.general.replacement; package de.jeremystartm.pickshadow.extension.command.general.replacement;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory; import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayerFactory;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -43,7 +42,7 @@ import static java.util.Map.entry;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class MessageCommand extends CommandBase { public final class MessageCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -67,12 +66,20 @@ public final class MessageCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public MessageCommand() throws IllegalArgumentException { public MessageCommand() throws IllegalArgumentException {
super("general", "message", "reply"); super(new Information(
"message",
new String[]{ "message", "msg", "whisper", "w", "reply", "r" },
"",
"",
"general",
null,
ExecutionTarget.PLAYERS_ONLY
), "message", "reply");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) throws Exception {
if (checkPermission(sender, "pickshadow.command.message")) return; if (checkPermission(sender, "pickshadow.command.message")) return;
if (sender instanceof Player player) if (sender instanceof Player player)
@ -122,10 +129,10 @@ public final class MessageCommand extends CommandBase {
receiver.sendRichMessage(output); receiver.sendRichMessage(output);
// Mark receiver as last contact // Mark receiver as last contact
PlayerDataFactory.getInstance().get(player).setLastMessaged(receiver.getUniqueId()); PSPlayerFactory.get(player).getData().setLastMessaged(receiver.getUniqueId());
} }
case "reply", "r" -> { case "reply", "r" -> {
UUID lastMessaged = PlayerDataFactory.getInstance().get(player).getLastMessaged(); UUID lastMessaged = PSPlayerFactory.get(player).getData().getLastMessaged();
if (lastMessaged == null) if (lastMessaged == null)
player.sendRichMessage(TranslationManager.get(LanguageString.MESSAGING_ERROR_NOLASTCONTACT, sender, true)); player.sendRichMessage(TranslationManager.get(LanguageString.MESSAGING_ERROR_NOLASTCONTACT, sender, true));

View file

@ -19,16 +19,17 @@
package de.jeremystartm.pickshadow.extension.command.general.replacement; package de.jeremystartm.pickshadow.extension.command.general.replacement;
import de.jeremystartm.pickshadow.extension.api.command.CommandBaseWithNull; import de.jeremystartm.pickshadow.extension.BuildOptions;
import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static java.util.Map.entry; import static java.util.Map.entry;
@ -38,18 +39,41 @@ import static java.util.Map.entry;
* @since v1-release0 * @since v1-release0
*/ */
@Getter @Getter
public final class PluginsCommand extends CommandBaseWithNull { @SuppressWarnings({ "JavadocDeclaration" })
public final class PluginsCommand extends Command {
/**
* Contains the tab completion for this command.
*
* @since v1-release0
* -- GETTER --
* Returns the tab completion for this command.
*
* @return tab completion
* @since v1-release0
*/
private final @NotNull TabCompletion completion = StubTabCompletion.completion();
/** /**
* Creates and initializes an instance of * Creates and initializes an instance of
* this class and registers this command. * this class and registers this command.
* *
* @since v1-release0 * @since v1-release0
*/ */
public PluginsCommand() {} public PluginsCommand() {
super(new Information(
"plugins",
new String[]{ "plugins", "pl" },
"",
"",
"general",
null,
ExecutionTarget.ALL
));
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @Nullable Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) throws Exception {
if (sender.hasPermission("pickshadow.command.plugins.real")) { if (sender.hasPermission("pickshadow.command.plugins.real")) {
StringBuilder output = new StringBuilder(); StringBuilder output = new StringBuilder();
Plugin[] plugins = Bukkit.getPluginManager().getPlugins(); Plugin[] plugins = Bukkit.getPluginManager().getPlugins();
@ -80,15 +104,18 @@ public final class PluginsCommand extends CommandBaseWithNull {
.append(plugin.isEnabled() ? "enabled": "disabled") .append(plugin.isEnabled() ? "enabled": "disabled")
.append(plugin.isNaggable() ? "": ", was nagged") .append(plugin.isNaggable() ? "": ", was nagged")
.append(")") .append(")")
.append(entrySuffix) .append(entrySuffix);
;
sender.sendRichMessage(output.toString()); sender.sendRichMessage(output.toString());
} else if (!checkPermission(sender, "pickshadow.command.plugins")) } else if (!checkPermission(sender, "pickshadow.command.plugins"))
sender.sendRichMessage(TranslationManager.get( sender.sendRichMessage(TranslationManager.get(
LanguageString.PLUGINS, LanguageString.PLUGINS_FAKE,
sender, sender,
true true,
entry("link_psse", BuildOptions.LINKS_PICKSHADOW_REPOSITORY),
entry("link_luckperms", BuildOptions.LINKS_LUCKPERMS),
entry("link_viaversion", BuildOptions.LINKS_VIAVERSION),
entry("link_freedomchat", BuildOptions.LINKS_FREEDOMCHAT)
)); ));
} }
} }

View file

@ -19,14 +19,14 @@
package de.jeremystartm.pickshadow.extension.command.general.replacement; package de.jeremystartm.pickshadow.extension.command.general.replacement;
import de.jeremystartm.pickshadow.extension.api.command.CommandBaseWithNull; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Handles the {@code /reload} command. * Handles the {@code /reload} command.
@ -34,18 +34,41 @@ import org.jetbrains.annotations.Nullable;
* @since v1-release0 * @since v1-release0
*/ */
@Getter @Getter
public final class ReloadCommand extends CommandBaseWithNull { @SuppressWarnings({ "JavadocDeclaration" })
public final class ReloadCommand extends Command {
/**
* Contains the tab completion for this command.
*
* @since v1-release0
* -- GETTER --
* Returns the tab completion for this command.
*
* @return tab completion
* @since v1-release0
*/
private final @NotNull TabCompletion completion = StubTabCompletion.completion();
/** /**
* Creates and initializes an instance of * Creates and initializes an instance of
* this class and registers this command. * this class and registers this command.
* *
* @since v1-release0 * @since v1-release0
*/ */
public ReloadCommand() {} public ReloadCommand() {
super(new Information(
"reload",
new String[]{ "reload", "rl" },
"",
"",
"general",
null,
ExecutionTarget.ALL
));
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @Nullable Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) throws Exception {
if (checkPermission(sender, "pickshadow.command.reload")) return; if (checkPermission(sender, "pickshadow.command.reload")) return;
sender.sendRichMessage(TranslationManager.get(LanguageString.RELOAD, sender, true)); sender.sendRichMessage(TranslationManager.get(LanguageString.RELOAD, sender, true));

View file

@ -19,14 +19,13 @@
package de.jeremystartm.pickshadow.extension.command.survival; package de.jeremystartm.pickshadow.extension.command.survival;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -42,7 +41,7 @@ import static java.util.Map.entry;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class HomeCommand extends CommandBase { public final class HomeCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -62,12 +61,20 @@ public final class HomeCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public HomeCommand() throws IllegalArgumentException { public HomeCommand() throws IllegalArgumentException {
super("survival", "home"); super(new Information(
"home",
new String[]{ "home", "bed", "spawnpoint", "sp" },
"",
"",
"survival",
null,
ExecutionTarget.CONSOLE_PARTIAL
), "home");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.home")) return; if (checkPermission(sender, "pickshadow.command.home")) return;
boolean onSelf; boolean onSelf;

View file

@ -19,14 +19,13 @@
package de.jeremystartm.pickshadow.extension.command.survivalcheat; package de.jeremystartm.pickshadow.extension.command.survivalcheat;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -42,7 +41,7 @@ import static java.util.Map.entry;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class FeedCommand extends CommandBase { public final class FeedCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -63,12 +62,20 @@ public final class FeedCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public FeedCommand() throws IllegalArgumentException { public FeedCommand() throws IllegalArgumentException {
super("survivalcheat", "feed"); super(new Information(
"feed",
new String[]{ "feed" },
"",
"",
"survivalcheat",
null,
ExecutionTarget.CONSOLE_PARTIAL
), "feed");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.feed")) return; if (checkPermission(sender, "pickshadow.command.feed")) return;
Player player; Player player;
@ -116,10 +123,10 @@ public final class FeedCommand extends CommandBase {
player.setFoodLevel(20); player.setFoodLevel(20);
// Send success message // Send success message
player.sendRichMessage(TranslationManager.get(LanguageString.HEAL, player, true)); player.sendRichMessage(TranslationManager.get(LanguageString.FEED, player, true));
if (!onSelf) if (!onSelf)
sender.sendRichMessage(TranslationManager.get( sender.sendRichMessage(TranslationManager.get(
LanguageString.HEAL_REMOTE, LanguageString.FEED_REMOTE,
sender, sender,
true, true,
entry("player", player.getName()) entry("player", player.getName())

View file

@ -20,7 +20,7 @@
package de.jeremystartm.pickshadow.extension.command.survivalcheat; package de.jeremystartm.pickshadow.extension.command.survivalcheat;
import de.jeremystartm.pickshadow.extension.BuildOptions; import de.jeremystartm.pickshadow.extension.BuildOptions;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
@ -28,7 +28,6 @@ import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.attribute.Attribute; import org.bukkit.attribute.Attribute;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityRegainHealthEvent; import org.bukkit.event.entity.EntityRegainHealthEvent;
@ -50,7 +49,7 @@ import static java.util.Map.entry;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class HealCommand extends CommandBase { public final class HealCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -73,12 +72,20 @@ public final class HealCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public HealCommand() throws IllegalArgumentException { public HealCommand() throws IllegalArgumentException {
super("survivalcheat", "heal"); super(new Information(
"heal",
new String[]{ "heal" },
"",
"",
"survivalcheat",
null,
ExecutionTarget.CONSOLE_PARTIAL
), "heal");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.heal")) return; if (checkPermission(sender, "pickshadow.command.heal")) return;
Player player; Player player;

View file

@ -19,17 +19,14 @@
package de.jeremystartm.pickshadow.extension.command.survivalcheat; package de.jeremystartm.pickshadow.extension.command.survivalcheat;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Objects; import java.util.Objects;
@ -41,7 +38,7 @@ import java.util.Objects;
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class ToggleDownfallCommand extends CommandBase { public final class ToggleDownfallCommand extends Command {
/** /**
* Contains the tab completion for this command. * Contains the tab completion for this command.
* *
@ -61,29 +58,35 @@ public final class ToggleDownfallCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public ToggleDownfallCommand() throws IllegalArgumentException { public ToggleDownfallCommand() throws IllegalArgumentException {
super("survivalcheat", "toggledownfall"); super(new Information(
"toggledownfall",
new String[]{ "toggledownfall" },
"",
"",
"survivalcheat",
null,
ExecutionTarget.PLAYERS_ONLY
), "toggledownfall");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
@SuppressWarnings("resource") @SuppressWarnings("resource")
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { protected void invokePlayer(@NotNull PSPlayer player, @NotNull String alias, @NotNull String @NotNull [] arguments) {
if (!checkPermission(sender, "pickshadow.command.toggledownfall")) if (checkPermission(player, "pickshadow.command.toggledownfall")) return;
if (sender instanceof Player player) {
try { try {
ServerLevel level = Objects.requireNonNull(MinecraftServer.getServer().getPlayerList().getPlayer(player.getUniqueId())).serverLevel(); ServerLevel level = Objects.requireNonNull(MinecraftServer.getServer().getPlayerList().getPlayer(player.getUUID())).serverLevel();
if (player.getWorld().isClearWeather()) if (player.getWorld().isClearWeather())
level.setWeatherParameters(0, getDuration(), true, false); level.setWeatherParameters(0, getDuration(), true, false);
else else
level.setWeatherParameters(getDuration(), 0, false, false); level.setWeatherParameters(getDuration(), 0, false, false);
sender.sendRichMessage(TranslationManager.get(LanguageString.TOGGLEDOWNFALL, sender, false)); player.messageTranslatable(LanguageString.TOGGLEDOWNFALL, false);
} catch (Exception exception) { } catch (Exception exception) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNKNOWN, sender, true)); player.messageTranslatable(LanguageString.ERROR_UNKNOWN, true);
} }
} else
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true));
} }
/** /**

View file

@ -20,7 +20,9 @@
package de.jeremystartm.pickshadow.extension.listener; package de.jeremystartm.pickshadow.extension.listener;
import de.jeremystartm.pickshadow.extension.BuildOptions; import de.jeremystartm.pickshadow.extension.BuildOptions;
import de.jeremystartm.pickshadow.extension.api.command.CommandBaseWithNull; import de.jeremystartm.pickshadow.extension.api.command.Command;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayerFactory;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.jeremystartm.pickshadow.extension.command.general.replacement.PluginsCommand; import de.jeremystartm.pickshadow.extension.command.general.replacement.PluginsCommand;
@ -28,14 +30,13 @@ import de.jeremystartm.pickshadow.extension.command.general.replacement.ReloadCo
import de.staropensource.engine.base.logging.Logger; import de.staropensource.engine.base.logging.Logger;
import io.papermc.paper.event.player.AsyncChatEvent; import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Arrays; import static java.util.Map.entry;
/** /**
* Listens on chat events. * Listens on chat events.
@ -66,14 +67,21 @@ public final class ChatListener implements Listener {
*/ */
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void handleChatMessage(@NotNull AsyncChatEvent event) { public void handleChatMessage(@NotNull AsyncChatEvent event) {
PSPlayer player = PSPlayerFactory.get(event.getPlayer());
// Cancel chat message
event.setCancelled(true); event.setCancelled(true);
// Broadcast the message ourselves
if (!BuildOptions.SMALLSTUFF_CHAT_COMMENTS || !MiniMessage.miniMessage().serialize(event.originalMessage()).startsWith("#")) if (!BuildOptions.SMALLSTUFF_CHAT_COMMENTS || !MiniMessage.miniMessage().serialize(event.originalMessage()).startsWith("#"))
Bukkit.broadcast( PSPlayer.broadcast(
MiniMessage.miniMessage().deserialize( TranslationManager.get(
TranslationManager.get(LanguageString.MESSAGING_SERVER, event.getPlayer(), false) LanguageString.MESSAGING_SERVER,
.replace("%sender%", event.getPlayer().getName()) player.getBukkitPlayer(),
).append(MiniMessage.miniMessage().deserialize(MiniMessage.miniMessage().serialize(event.originalMessage()).replace("\\<", "<"))) false,
entry("sender", player.getUsername())
)
+ MiniMessage.miniMessage().serialize(event.originalMessage()).replace("\\<", "<")
); );
} }
@ -86,15 +94,23 @@ public final class ChatListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void handleChatCommand(@NotNull PlayerCommandPreprocessEvent event) { public void handleChatCommand(@NotNull PlayerCommandPreprocessEvent event) {
try { try {
PSPlayer player = PSPlayerFactory.get(event.getPlayer());
String[] arguments = event.getMessage().split(" "); String[] arguments = event.getMessage().split(" ");
String command = arguments[0]; String command = arguments[0];
// Disallow any usage of namespaces
// This prevents the use of deprecated,
// legacy, overriden or unsafe commands.
// Or in other words: It allows full control
// over what commands players can execute.
if (command.contains(":")) { if (command.contains(":")) {
event.setCancelled(true); event.setCancelled(true);
event.getPlayer().sendRichMessage(TranslationManager.get(LanguageString.CHATCOMMAND_ERROR_NAMESPACE, event.getPlayer(), true)); player.messageTranslatable(LanguageString.CHATCOMMAND_ERROR_NAMESPACE, true);
} }
// Override commands // Override Bukkit commands
// These cannot be overridden by using the
// plugin.yml file and the PluginCommand class
forceOverrideCommand(event, arguments, pluginsCommand, "plugins", "pl"); forceOverrideCommand(event, arguments, pluginsCommand, "plugins", "pl");
forceOverrideCommand(event, arguments, reloadCommand, "reload", "rl"); forceOverrideCommand(event, arguments, reloadCommand, "reload", "rl");
} catch (Exception exception) { } catch (Exception exception) {
@ -109,11 +125,11 @@ public final class ChatListener implements Listener {
* @param event event information * @param event event information
* @since v1-release0 * @since v1-release0
*/ */
private static void forceOverrideCommand(@NotNull PlayerCommandPreprocessEvent event, @NotNull String @NotNull [] arguments, @NotNull CommandBaseWithNull commandBase, @NotNull String... commands) { private static void forceOverrideCommand(@NotNull PlayerCommandPreprocessEvent event, @NotNull String @NotNull [] arguments, @NotNull Command command, @NotNull String... commands) {
for (String command : commands) for (String commandOverride : commands)
if (arguments[0].equals("/" + command)) { if (arguments[0].equals("/" + commandOverride)) {
event.setCancelled(true); event.setCancelled(true);
commandBase.invoke(event.getPlayer(), null, command.substring(1), Arrays.copyOf(arguments, 1)); command.invoke(event.getPlayer(), commandOverride, arguments);
} }
} }
} }

View file

@ -21,7 +21,8 @@ package de.jeremystartm.pickshadow.extension.listener;
import de.jeremystartm.pickshadow.extension.BuildOptions; import de.jeremystartm.pickshadow.extension.BuildOptions;
import de.jeremystartm.pickshadow.extension.Extension; import de.jeremystartm.pickshadow.extension.Extension;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory; import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayerFactory;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.jeremystartm.pickshadow.extension.command.general.ClearChatCommand; import de.jeremystartm.pickshadow.extension.command.general.ClearChatCommand;
@ -29,7 +30,6 @@ import de.jeremystartm.pickshadow.extension.misc.Scheduler;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -56,31 +56,29 @@ public final class ConnectionListener implements Listener {
private void handlePlayerJoinEarly(@NotNull PlayerJoinEvent event) { private void handlePlayerJoinEarly(@NotNull PlayerJoinEvent event) {
try { try {
// Register player // Register player
PlayerDataFactory.getInstance().registerPlayer(event.getPlayer()); PSPlayer player = PSPlayerFactory.registerPlayer(event.getPlayer());
// Reset fall distance // Reset fall distance
// This effectively reintroduces MC-212, // This effectively reintroduces MC-212,
// which was fixed in 24w45a. // which was fixed in 24w45a.
if (BuildOptions.UNFIX_FALLDAMAGE_CANCELLING) if (BuildOptions.UNFIX_FALLDAMAGE_CANCELLING)
event.getPlayer().setFallDistance(0f); player.setFallDistance(0f);
// Launch scheduler // Launch scheduler
Scheduler.player(event.getPlayer()); Scheduler.player(player);
// Empty join message // Empty join message
event.joinMessage(Component.empty()); event.joinMessage(Component.empty());
// Broadcast our own join message // Broadcast our own join message
for (Player player : Bukkit.getOnlinePlayers()) PSPlayer.broadcastTranslatable(
player.sendRichMessage(TranslationManager.get(
LanguageString.CONNECTION_JOIN, LanguageString.CONNECTION_JOIN,
player,
false, false,
entry("player", event.getPlayer().getName()) entry("player", player.getUsername())
)); );
// Schedule late join event // Schedule late join event
event.getPlayer().getScheduler().execute(Extension.getInstance(), () -> handlePlayerJoinLate(event.getPlayer()), null, 1); event.getPlayer().getScheduler().execute(Extension.getInstance(), () -> handlePlayerJoinLate(player), null, 1);
} catch (Exception exception) { } catch (Exception exception) {
event.getPlayer().kick(MiniMessage.miniMessage().deserialize(TranslationManager.get(LanguageString.CONNECTION_ERROR_REGISTRATION, event.getPlayer(), false)), PlayerKickEvent.Cause.UNKNOWN); event.getPlayer().kick(MiniMessage.miniMessage().deserialize(TranslationManager.get(LanguageString.CONNECTION_ERROR_REGISTRATION, event.getPlayer(), false)), PlayerKickEvent.Cause.UNKNOWN);
} }
@ -88,17 +86,18 @@ public final class ConnectionListener implements Listener {
/** /**
* Handles player joins late. * Handles player joins late.
* *
* @param player {@link Player} which joined * @param player {@link PSPlayer} instance of the player which joined
* @since v1-release0 * @since v1-release0
*/ */
private void handlePlayerJoinLate(@NotNull Player player) { private void handlePlayerJoinLate(@NotNull PSPlayer player) {
// Clear chat and display welcome message // Clear chat and display welcome message
player.sendRichMessage(ClearChatCommand.NEWLINES + "\n" + TranslationManager.get( player.messageRaw(ClearChatCommand.NEWLINES);
player.messageTranslatable(
LanguageString.CONNECTION_JOIN_WELCOME, LanguageString.CONNECTION_JOIN_WELCOME,
player, false, false,
entry("player", player.getName()), entry("player", player.getUsername()),
entry("minecraftVersion", Bukkit.getMinecraftVersion()) entry("minecraftVersion", Bukkit.getMinecraftVersion())
)); );
} }
/** /**
@ -109,20 +108,19 @@ public final class ConnectionListener implements Listener {
*/ */
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
private void handlePlayerLeave(@NotNull PlayerQuitEvent event) { private void handlePlayerLeave(@NotNull PlayerQuitEvent event) {
// Unregister player PSPlayer player = PSPlayerFactory.get(event.getPlayer());
PlayerDataFactory.getInstance().unregisterPlayer(PlayerDataFactory.getInstance().get(event.getPlayer()));
// Empty quit message // Empty quit message
event.quitMessage(Component.empty()); event.quitMessage(Component.empty());
// Broadcast our own quit message // Broadcast our own quit message
for (Player player : Bukkit.getOnlinePlayers()) PSPlayer.broadcastTranslatable(
if (!player.getUniqueId().equals(event.getPlayer().getUniqueId()))
player.sendRichMessage(TranslationManager.get(
LanguageString.CONNECTION_DISCONNECT, LanguageString.CONNECTION_DISCONNECT,
player,
false, false,
entry("player", event.getPlayer().getName()) entry("player", player.getUsername())
)); );
// Unregister player
PSPlayerFactory.unregisterPlayer(player);
} }
} }

View file

@ -0,0 +1,103 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.extension.misc;
import de.jeremystartm.pickshadow.extension.BuildOptions;
import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer;
import de.jeremystartm.pickshadow.extension.api.type.PlayerDamageState;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.damage.DamageSource;
import org.bukkit.damage.DamageType;
import org.jetbrains.annotations.NotNull;
import static de.jeremystartm.pickshadow.extension.api.type.PlayerDamageState.*;
/**
* Handles player damage detection.
*
* @since v1-release0
*/
public final class DamageDetection {
/**
* Creates and initializes an
* instance of this class.
*
* @since v1-release0
*/
private DamageDetection() {}
/**
* Applies damage detection.
*
* @param player {@link PSPlayer} to apply damage detection to
* @since v1-release0
*/
public static void apply(@NotNull PSPlayer player) {
if (player.getGamemode() == GameMode.SURVIVAL || player.getGamemode() == GameMode.ADVENTURE)
DamageDetection.applyStonecutterDamage(player);
else
DamageDetection.resetDamageStates(player);
}
/**
* Applies stonecutter damage.
*
* @param player {@link PSPlayer} to apply stonecutter damage to
* @since v1-release0
*/
public static void applyStonecutterDamage(@NotNull PSPlayer player) {
if (BuildOptions.SMALLSTUFF_STONECUTTER_DAMAGE)
switch (player.getData().getDamageState(STONECUTTER)) {
case -1 -> {
Location location = player.getPosition().clone();
location.setX((long) location.getX() - 1);
location.setY(((long) location.getY()));
location.setZ((long) location.getZ());
if (player.getWorld().getBlockAt(location).getType() == Material.STONECUTTER) {
player.getData().setDamageState(STONECUTTER, 0);
//noinspection UnstableApiUsage
player.damage(
4,
DamageSource
.builder(DamageType.CACTUS)
.withDamageLocation(location)
.build()
);
}
}
case 11 -> player.getData().nullifyDamageState(STONECUTTER);
default -> player.getData().increaseDamageState(STONECUTTER);
}
}
/**
* Resets all damage states.
*
* @param player {@link PSPlayer} to reset states of
* @since v1-release0
*/
public static void resetDamageStates(@NotNull PSPlayer player) {
for (PlayerDamageState damageState : PlayerDamageState.values())
player.getData().nullifyDamageState(damageState);
}
}

View file

@ -21,18 +21,14 @@ package de.jeremystartm.pickshadow.extension.misc;
import de.jeremystartm.pickshadow.extension.BuildOptions; import de.jeremystartm.pickshadow.extension.BuildOptions;
import de.jeremystartm.pickshadow.extension.Extension; import de.jeremystartm.pickshadow.extension.Extension;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerData; import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.staropensource.engine.base.logging.Logger; import de.staropensource.engine.base.logging.Logger;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.luckperms.api.util.Tristate;
import org.bukkit.Bukkit; import org.bukkit.*;
import org.bukkit.Location; import org.bukkit.entity.Bat;
import org.bukkit.Material; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
@ -49,6 +45,7 @@ public final class Scheduler {
*/ */
private Scheduler() {} private Scheduler() {}
// -----> Scheduler methods
/** /**
* Invokes scheduler actions for the entire server. * Invokes scheduler actions for the entire server.
* *
@ -56,8 +53,12 @@ public final class Scheduler {
* @since v1-release0 * @since v1-release0
*/ */
public static void server(@NotNull ScheduledTask scheduledTask) { public static void server(@NotNull ScheduledTask scheduledTask) {
try {
for (World world : Bukkit.getServer().getWorlds()) for (World world : Bukkit.getServer().getWorlds())
world(world); world(world);
} catch (Exception exception) {
Logger.crash("Server scheduler failed", exception);
}
} }
/** /**
@ -66,7 +67,11 @@ public final class Scheduler {
* @since v1-release0 * @since v1-release0
*/ */
public static void world(@NotNull World world) { public static void world(@NotNull World world) {
try {
killBats(world);
} catch (Exception exception) {
Logger.crash("World scheduler failed for '" + world.getName() + "'", exception);
}
} }
/** /**
@ -75,35 +80,49 @@ public final class Scheduler {
* @param player player to invoke scheduler actions on * @param player player to invoke scheduler actions on
* @since v1-release0 * @since v1-release0
*/ */
public static void player(@NotNull Player player) { public static void player(@NotNull PSPlayer player) {
try { try {
PlayerData data = PlayerDataFactory.getInstance().get(player); // Apply all attributes
player.applyPlayerAttributes();
// Apply stonecutter damage // Apply damage
if (BuildOptions.SMALLSTUFF_STONECUTTER_DAMAGE) DamageDetection.apply(player);
switch (data.getStonecutterDamageState()) {
case -1 -> {
Location location = player.getLocation().clone();
location.setX((long) location.getX() - 1);
location.setY(((long) location.getY()));
location.setZ((long) location.getZ());
if (player.getWorld().getBlockAt(location).getType() == Material.STONECUTTER) {
data.setStonecutterDamageState(0);
player.damage(1);
}
}
case 11 -> data.setStonecutterDamageState(-1);
default -> data.setStonecutterDamageState(data.getStonecutterDamageState() + 1);
}
// Reschedule // Reschedule
player.getScheduler().execute(Extension.getInstance(), () -> player(player), null, 1L); player.schedule(() -> player(player), 1L);
} catch (Exception exception) { } catch (Exception exception) {
if (player.isOnline()) if (player.isOnline())
player.kick(MiniMessage.miniMessage().deserialize(TranslationManager.get(LanguageString.CONNECTION_ERROR_SCHEDULER, player, false))); player.kickTranslatable(LanguageString.CONNECTION_ERROR_SCHEDULER);
Logger.crash("Player scheduler failed for " + player.getName() + " [" + player.getUniqueId() + "]", exception, false); Logger.crash("Player scheduler failed for '" + player.getUsername() + "' [" + player.getUUID() + "]", exception, false);
}
}
// -----> Scheduler actions
/**
* Kills all bats in the specified world.
*
* @param world world to kill all bats in
* @since v1-release0
*/
private static void killBats(@NotNull World world) {
if (BuildOptions.SMALLSTUFF_KILL_BATS != Tristate.FALSE) {
Location location;
for (Bat bat : world.getEntitiesByClass(Bat.class)) {
// Only include naturally spawned bats
if (BuildOptions.SMALLSTUFF_KILL_BATS == Tristate.UNDEFINED && bat.getEntitySpawnReason() != CreatureSpawnEvent.SpawnReason.NATURAL)
continue;
// Teleport bat under the world
location = bat.getLocation().clone();
location.setY(world.getMinHeight() - 4);
if (!bat.teleport(location))
Logger.diag("Teleport of bat " + bat.getUniqueId() + " failed (currently at " + bat.getLocation() + ")");
// Kill bat
bat.getScheduler().execute(Extension.getInstance(), () -> bat.setHealth(0), null, 1L);
}
} }
} }
} }

View file

@ -19,8 +19,8 @@
package de.jeremystartm.pickshadow.extension.misc; package de.jeremystartm.pickshadow.extension.misc;
import de.jeremystartm.pickshadow.extension.Extension; import de.jeremystartm.pickshadow.extension.BuildOptions;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerData; import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer;
import de.staropensource.engine.base.logging.Logger; import de.staropensource.engine.base.logging.Logger;
import fr.mrmicky.fastboard.adventure.FastBoard; import fr.mrmicky.fastboard.adventure.FastBoard;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
@ -88,43 +88,39 @@ public final class TabListHandler {
} }
/** /**
* Initializes the tab list for * Initializes the tab list
* some {@link PlayerData} instance. * for the specified player.
* *
* @param player {@link PSPlayer} to initialize the tab list for
* @since v1-release0 * @since v1-release0
*/ */
public void initializeTabList(@NotNull PlayerData playerData) { public void initializeTabList(@NotNull PSPlayer player) {
Logger.verb("Initializing player list for player " + playerData.getPlayer().getName() + " (" + playerData.getPlayer().getUniqueId() + ")"); Logger.verb("Initializing player list for player " + player.getIdentificationString());
// Initialize FastBoard // Initialize FastBoard
FastBoard board = new FastBoard(playerData.getPlayer()); FastBoard board = new FastBoard(player.getBukkitPlayer());
playerData.setPlayerListScoreboard(board); player.getData().setPlayerListScoreboard(board);
// Configure FastBoard // Configure FastBoard
board.updateTitle(MiniMessage.miniMessage().deserialize("<red>TabList <italic>yay</italic></red>")); board.updateTitle(MiniMessage.miniMessage().deserialize("<red>TabList <italic>yay</italic></red>"));
// Schedule update // Schedule update
updateTabList(playerData, true); player.scheduleRepeatedly(() -> updateTabList(player), BuildOptions.SETTINGS_TABLIST_UPDATERATE);
updateTabList(player);
} }
/** /**
* Updates the tab list. * Updates the tab list.
* *
* @param player {@link PSPlayer} to update the tab list for
* @since v1-release0 * @since v1-release0
*/ */
public void updateTabList(@NotNull PlayerData playerData, boolean justSchedule) { public void updateTabList(@NotNull PSPlayer player) {
// Schedule next update Logger.verb("Updating player list for player " + player.getIdentificationString());
playerData.getPlayer().getScheduler().execute(Extension.getInstance(), () -> updateTabList(playerData, false), null, 20);
// Stop further execution if 'justSchedule' is true
if (justSchedule)
return;
Logger.verb("Updating player list for player " + playerData.getPlayer().getName() + " (" + playerData.getPlayer().getUniqueId() + ")");
for (int line = 0; line < content.size(); line++) { for (int line = 0; line < content.size(); line++) {
Logger.verb("Processing line " + line + " for player " + playerData.getPlayer().getName() + " (" + playerData.getPlayer().getUniqueId() + ")"); Logger.verb("Processing line " + line + " for player " + player.getIdentificationString());
playerData.getPlayerListScoreboard().updateLine(line, MiniMessage.miniMessage().deserialize(content.get(line))); player.getData().getPlayerListScoreboard().updateLine(line, MiniMessage.miniMessage().deserialize(content.get(line)));
} }
} }
} }

View file

@ -74,6 +74,11 @@ commands:
description: "Displays the IP address to PickShadow's Mumble server." description: "Displays the IP address to PickShadow's Mumble server."
usage: "/mumble" usage: "/mumble"
aliases: [] aliases: []
# -> SpeedCommand
speed:
description: "Allows changing the walk and fly speed of players."
usage: "/speed <walk|fly> <default|0.0-1.0> [player]"
aliases: []
# -> TrollCommand # -> TrollCommand
troll: troll:
description: "Various torturing methods for misbehaving players ;)" description: "Various torturing methods for misbehaving players ;)"
@ -184,6 +189,16 @@ permissions:
pickshadow.command.link: pickshadow.command.link:
description: "Provides access to multiple commands returning hyperlinks." description: "Provides access to multiple commands returning hyperlinks."
default: false default: false
# --> SpeedCommand
pickshadow.command.speed:
description: "Provides access to the '/speed' command."
default: false
pickshadow.command.speed.fly:
description: "Provides acess to '/speed''s 'fly' option."
default: false
pickshadow.command.speed.walk:
description: "Provides acess to '/speed''s 'walk' option."
default: false
# --> TrollCommand # --> TrollCommand
pickshadow.command.troll: pickshadow.command.troll:
description: "Provides access to the '/troll' command." description: "Provides access to the '/troll' command."

View file

@ -3,10 +3,11 @@
"ERROR_UNIMPLEMENTED": "<error>Diese Aktion wurde noch nicht implementiert.</error>", "ERROR_UNIMPLEMENTED": "<error>Diese Aktion wurde noch nicht implementiert.</error>",
"ERROR_INVALID_MODE": "<error>Diese Aktion ist nicht verfügbar, da sie deaktiviert wurde.</error>", "ERROR_INVALID_MODE": "<error>Diese Aktion ist nicht verfügbar, da sie deaktiviert wurde.</error>",
"ERROR_NOT_A_PLAYER": "<error>Ein Spieler ist für diese Aktion benötigt.</error>", "ERROR_NOT_A_PLAYER": "<error>Ein Spieler ist für diese Aktion benötigt.</error>",
"ERROR_NOT_SERVER_CONSOLE": "<error>Diese Aktion erfordert die Ausführung von der Serverkonsole.</error>",
"ERROR_MISSING_PERM": "<error>Dir ist es nicht erlaubt, diese Aktion durchzuführen (%permission% fehlt).</error>", "ERROR_MISSING_PERM": "<error>Dir ist es nicht erlaubt, diese Aktion durchzuführen (%permission% fehlt).</error>",
"ERROR_TOO_FEW_ARGUMENTS": "<error>Zu wenige Argumente.</error>", "ERROR_TOO_FEW_ARGUMENTS": "<error>Zu wenige Argumente.</error>",
"ERROR_TOO_MANY_ARGUMENTS": "<error>Zu viele Argumente.</error>", "ERROR_TOO_MANY_ARGUMENTS": "<error>Zu viele Argumente.</error>",
"ERROR_INVALID_ARGUMENT": "<error>Ungültige(s) Argument(e) <mention>%argument%</mention>.</error>", "ERROR_INVALID_ARGUMENT": "<error>Ungültige(s) Argument(e) '<mention>%argument%</mention>'.</error>",
"ERROR_PLAYER_NOT_FOUND": "<error>Der Spieler <mention>%player%</mention> konnte nicht gefunden werden.</error>", "ERROR_PLAYER_NOT_FOUND": "<error>Der Spieler <mention>%player%</mention> konnte nicht gefunden werden.</error>",
"CONNECTION_JOIN": "<generic><mention>%player%</mention> ist dem Spiel beigetreten</generic>", "CONNECTION_JOIN": "<generic><mention>%player%</mention> ist dem Spiel beigetreten</generic>",
@ -20,7 +21,8 @@
"EXTENSIONCMD_KILLJVM": "<generic>Bye bye!</generic>", "EXTENSIONCMD_KILLJVM": "<generic>Bye bye!</generic>",
"EXTENSIONCMD_LICENSE": "<generic>PSSE ist lizensiert unter der <click:open_url:%license_url%><link>%license%</link></click>.</generic>", "EXTENSIONCMD_LICENSE": "<generic>PSSE ist lizensiert unter der <click:open_url:%license_url%><link>%license%</link></click>.</generic>",
"EXTENSIONCMD_SOURCE": "<generic>Du kannst PickShadow's serverseitigen Code auf <click:open_url:%source%><link>sos!git</link></click> finden.</generic>", "EXTENSIONCMD_SOURCE": "<generic>Du kannst PickShadow's serverseitigen Code auf <click:open_url:%source%><link>sos!git</link></click> finden.</generic>",
"EXTENSIONCMD_ERROR_OLDCMD": "<error>Was ist <mention>PSSP</mention>...?</error>\n<error>Das PickShadow Server Plugin (PSSP) wurde in PickShadow Server <italic>Extension</italic> (PSSE) umbenannt.</error>\n<error>Bitte verwende diesen Namen stattdessen, vielen Dank.</error>",
"LEGACYEXTENSIONCMD": "<error>Was ist <mention>PSSP</mention>...?</error>\n<error>Das PickShadow Server Plugin (PSSP) wurde in PickShadow Server <italic>Extension</italic> (PSSE) umbenannt.</error>\n<error>Bitte verwende diesen Namen stattdessen, vielen Dank.</error>",
"MESSAGING_LASTCONTACT": "<generic>Die letzte Person, die du angeschrieben hast ist <mention>%contact%</mention>.</generic>", "MESSAGING_LASTCONTACT": "<generic>Die letzte Person, die du angeschrieben hast ist <mention>%contact%</mention>.</generic>",
"MESSAGING_ERROR_SELF": "<error>Du kannst dich nicht selber anschreiben.</error>", "MESSAGING_ERROR_SELF": "<error>Du kannst dich nicht selber anschreiben.</error>",
@ -59,8 +61,11 @@
"HEAL": "<generic>Du wurdest geheilt.</generic>", "HEAL": "<generic>Du wurdest geheilt.</generic>",
"HEAL_REMOTE": "<generic><mention>%player%</mention> wurde geheilt.</generic>", "HEAL_REMOTE": "<generic><mention>%player%</mention> wurde geheilt.</generic>",
"FEED": "<generic>Du wurdest gefüttert.</generic>",
"FEED_REMOTE": "<generic><mention>%player%</mention> wurde gefüttert.</generic>",
"PLUGINS": "<generic><mention>%count%</mention> Erweiterungen sind auf diesem Subserver installiert, welche sind:</generic>", "PLUGINS": "<generic><mention>%count%</mention> Erweiterungen sind auf diesem Subserver installiert, welche sind:</generic>",
"PLUGINS_FAKE": "<generic>Denkst du wirklich, dass du interne Informationen so einfach bekommen kannst?</generic>\n<generic>Glücklicherweise sind wir keine Arschlöcher und geben an was wir verwenden.\n<generic>Das PickShadow Netzwerk verwendet <click:open_url:%link_psse%><link>PSSE</link></click>, <click:open_url:%link_luckperms%><link>LuckPerms</link></click> und <click:open_url:%link_freedomchat%><link>FreedomChat</link></click> um Subserver zu verwalten.", "PLUGINS_FAKE": "<generic>Denkst du wirklich, dass du interne Informationen so einfach bekommen kannst?</generic>\n<generic>Glücklicherweise sind wir keine Arschlöcher und geben an was wir verwenden.\n<generic>Das PickShadow Team setzt <click:open_url:%link_psse%><link>PSSE</link></click>, <click:open_url:%link_luckperms%><link>LuckPerms</link></click>, <click:open_url:%link_viaversion%><link>ViaVersion</link></click> und <click:open_url:%link_freedomchat%><link>FreedomChat</link></click> ein, um das Netzwerk zu verwalten.",
"RELOAD": "<error>Server reloads gelten als unsicher und werden daher von PSSE blockiert.</error>\n<error>Bitte starte den Subserver stattdessen neu.</error>\n<error>Für mehr Informationen, lese bitte den folgenden Blogartikel (Englisch):</error>\n<error>https://madelinemiller.dev/blog/problem-with-reload/</error>", "RELOAD": "<error>Server reloads gelten als unsicher und werden daher von PSSE blockiert.</error>\n<error>Bitte starte den Subserver stattdessen neu.</error>\n<error>Für mehr Informationen, lese bitte den folgenden Blogartikel (Englisch):</error>\n<error>https://madelinemiller.dev/blog/problem-with-reload/</error>",
@ -71,5 +76,10 @@
"GAMEMODE_ADVENTURE": "Abenteuermodus", "GAMEMODE_ADVENTURE": "Abenteuermodus",
"GAMEMODE_SPECTATOR": "Zuschauermodus", "GAMEMODE_SPECTATOR": "Zuschauermodus",
"SPEED": "<generic>Deine <mention>%mode%</mention> wurde auf <mention>%speed%</mention> geändert.</generic>",
"SPEED_REMOTE": "<generic>Die <mention>%mode%</mention> von <mention>%player%</mention> wurde auf <mention>%speed%</mention> geändert.</generic>",
"SPEED_FLY": "Fluggeschwindigkeit",
"SPEED_WALK": "Laufgeschwindigkeit",
"CHATCOMMAND_ERROR_NAMESPACE": "<error>Namespaces zu verwenden ist nicht erlaubt, da es verwendet werden kann um Sicherheitsmaßnahmen zu umgehen.</error>" "CHATCOMMAND_ERROR_NAMESPACE": "<error>Namespaces zu verwenden ist nicht erlaubt, da es verwendet werden kann um Sicherheitsmaßnahmen zu umgehen.</error>"
} }

View file

@ -15,10 +15,11 @@
"ERROR_UNIMPLEMENTED": "<error>This action is not yet implemented.</error>", "ERROR_UNIMPLEMENTED": "<error>This action is not yet implemented.</error>",
"ERROR_INVALID_MODE": "<error>This action is unavailable due to it being disabled.</error>", "ERROR_INVALID_MODE": "<error>This action is unavailable due to it being disabled.</error>",
"ERROR_NOT_A_PLAYER": "<error>You must be a player to perform this action.</error>", "ERROR_NOT_A_PLAYER": "<error>You must be a player to perform this action.</error>",
"ERROR_NOT_SERVER_CONSOLE": "<error>This action must be invoked from the server console.</error>",
"ERROR_MISSING_PERM": "<error>You aren't allowed to perform this action (lacking <mention>%permission%</mention>).</error>", "ERROR_MISSING_PERM": "<error>You aren't allowed to perform this action (lacking <mention>%permission%</mention>).</error>",
"ERROR_TOO_FEW_ARGUMENTS": "<error>Too few arguments.</error>", "ERROR_TOO_FEW_ARGUMENTS": "<error>Too few arguments.</error>",
"ERROR_TOO_MANY_ARGUMENTS": "<error>Too many arguments.</error>", "ERROR_TOO_MANY_ARGUMENTS": "<error>Too many arguments.</error>",
"ERROR_INVALID_ARGUMENT": "<error>Invalid argument(s) <mention>%argument%</mention>.</error>", "ERROR_INVALID_ARGUMENT": "<error>Invalid argument(s) '<mention>%argument%</mention>'.</error>",
"ERROR_PLAYER_NOT_FOUND": "<error>The player <mention>%player%</mention> could not be found.</error>", "ERROR_PLAYER_NOT_FOUND": "<error>The player <mention>%player%</mention> could not be found.</error>",
"CONNECTION_JOIN": "<generic><mention>%player%</mention> joined the game</generic>", "CONNECTION_JOIN": "<generic><mention>%player%</mention> joined the game</generic>",
@ -32,7 +33,8 @@
"EXTENSIONCMD_KILLJVM": "<generic>Bye bye!</generic>", "EXTENSIONCMD_KILLJVM": "<generic>Bye bye!</generic>",
"EXTENSIONCMD_LICENSE": "<generic>PSSE is licensed under the <click:open_url:%license_url%><link>%license%</link></click>.</generic>", "EXTENSIONCMD_LICENSE": "<generic>PSSE is licensed under the <click:open_url:%license_url%><link>%license%</link></click>.</generic>",
"EXTENSIONCMD_SOURCE": "<generic>You can find the source code of PickShadow's server-side code on <click:open_url:%source%><link>sos!git</link></click>.</generic>", "EXTENSIONCMD_SOURCE": "<generic>You can find the source code of PickShadow's server-side code on <click:open_url:%source%><link>sos!git</link></click>.</generic>",
"EXTENSIONCMD_ERROR_OLDCMD": "<error>What's <mention>PSSP</mention>...?</error>\n<error>The PickShadow Server <italic>Plugin</italic> (PSSP) has been renamed into PickShadow Server <italic>Extension</italic> (PSSE).</error>\n<error>Please use the new name from now on. Thank you.</error>",
"LEGACYEXTENSIONCMD": "<error>What's <mention>PSSP</mention>...?</error>\n<error>The PickShadow Server <italic>Plugin</italic> (PSSP) has been renamed into PickShadow Server <italic>Extension</italic> (PSSE).</error>\n<error>Please use the new name from now on. Thank you.</error>",
"MESSAGING_SERVER": "<mention>%sender%</mention> <#d60532>»</#d60532> ", "MESSAGING_SERVER": "<mention>%sender%</mention> <#d60532>»</#d60532> ",
"MESSAGING_DIRECT": "<generic><mention>%from%</mention> » <mention>%to%</mention> » </generic>%message%", "MESSAGING_DIRECT": "<generic><mention>%from%</mention> » <mention>%to%</mention> » </generic>%message%",
@ -75,7 +77,7 @@
"HEAL_REMOTE": "<generic><mention>%player%</mention> has been healed.</generic>", "HEAL_REMOTE": "<generic><mention>%player%</mention> has been healed.</generic>",
"PLUGINS": "<generic><mention>%count%</mention> extensions are installed on this subserver, these being:</generic>", "PLUGINS": "<generic><mention>%count%</mention> extensions are installed on this subserver, these being:</generic>",
"PLUGINS_FAKE": "<generic>Do you really think you can get internal information so easily?</generic>\n<generic>Luckily, we aren't dicks and credit what we use.\n<generic>The PickShadow network uses <click:open_url:%link_psse%><link>PSSE</link></click>, <click:open_url:%link_luckperms%><link>LuckPerms</link></click> and <click:open_url:%link_freedomchat%><link>FreedomChat</link></click> to manage subservers.", "PLUGINS_FAKE": "<generic>Do you really think you can get internal information so easily?</generic>\n<generic>Luckily, we aren't dicks and credit what we use.\n<generic>The PickShadow network uses <click:open_url:%link_psse%><link>PSSE</link></click>, <click:open_url:%link_luckperms%><link>LuckPerms</link></click>, <click:open_url:%link_viaversion%><link>ViaVersion</link></click> and <click:open_url:%link_freedomchat%><link>FreedomChat</link></click> to manage subservers.",
"PLUGINS_ENTRY_PREFIX": "<generic>- ", "PLUGINS_ENTRY_PREFIX": "<generic>- ",
"PLUGINS_ENTRY_SUFFIX": "</generic>", "PLUGINS_ENTRY_SUFFIX": "</generic>",
"PLUGINS_ENTRY_NAME_PREFIX": "<mention>", "PLUGINS_ENTRY_NAME_PREFIX": "<mention>",
@ -90,5 +92,10 @@
"GAMEMODE_ADVENTURE": "Adventure mode", "GAMEMODE_ADVENTURE": "Adventure mode",
"GAMEMODE_SPECTATOR": "Spectator mode", "GAMEMODE_SPECTATOR": "Spectator mode",
"SPEED": "<generic>Your <mention>%mode%</mention> was changed to <mention>%speed%</mention>.</generic>",
"SPEED_REMOTE": "<generic>The <mention>%mode%</mention> of <mention>%player%</mention> was changed to <mention>%speed%</mention>.</generic>",
"SPEED_FLY": "fly speed",
"SPEED_WALK": "walk speed",
"CHATCOMMAND_ERROR_NAMESPACE": "<error>Using namespaces is not allowed, as it may be used to circumvent security measures.</error>" "CHATCOMMAND_ERROR_NAMESPACE": "<error>Using namespaces is not allowed, as it may be used to circumvent security measures.</error>"
} }