From 44fd5ed4279fe67f35cca16646502e46322f05a9 Mon Sep 17 00:00:00 2001 From: JeremyStarTM Date: Thu, 21 Nov 2024 15:14:57 +0100 Subject: [PATCH] Add server modes, more event listeners and more --- dist/methodmaps/PSPlayer.csv | 3 + .../pickshadow/extension/BuildOptions.java | 26 +- .../pickshadow/extension/Extension.java | 51 ++- .../extension/ExtensionConfiguration.java | 81 +++- .../extension/api/command/Command.java | 77 +++- .../extension/api/entity/player/PSPlayer.java | 40 +- .../api/translation/LanguageString.java | 13 +- .../extension/command/TemplateCommand.java | 2 +- .../command/general/AnnounceCommand.java | 2 +- .../command/general/ClearChatCommand.java | 2 +- .../command/general/ExtensionCommand.java | 77 +++- .../command/general/LanguageCommand.java | 2 +- .../general/LegacyExtensionCommand.java | 2 +- .../command/general/LinkCommand.java | 2 +- .../command/general/SpeedCommand.java | 2 +- .../command/general/TrollCommand.java | 6 +- .../general/replacement/GamemodeCommand.java | 6 +- .../general/replacement/HelpCommand.java | 2 +- .../general/replacement/MessageCommand.java | 2 +- .../general/replacement/PluginsCommand.java | 2 +- .../general/replacement/ReloadCommand.java | 2 +- .../extension/command/multi/SpawnCommand.java | 128 ++++++ .../command/survival/HomeCommand.java | 2 +- .../command/survivalcheat/FeedCommand.java | 2 +- .../command/survivalcheat/HealCommand.java | 2 +- .../survivalcheat/ToggleDownfallCommand.java | 2 +- .../extension/implementable/ServerMode.java | 372 ++++++++++++++++++ .../extension/implementable/package-info.java | 25 ++ .../implementation/mode/GeneralMode.java | 60 +++ .../implementation/mode/HubMode.java | 186 +++++++++ .../mode/SurvivalCheatMode.java | 57 +++ .../implementation/mode/SurvivalMode.java | 57 +++ .../implementation/mode/package-info.java | 25 ++ .../implementation/package-info.java | 25 ++ .../extension/listener/ChatListener.java | 14 + .../listener/ConnectionListener.java | 24 +- .../listener/PlayerEventListener.java | 80 ++++ .../listener/WorldEventListener.java | 199 ++++++++++ .../extension/misc/Miscellaneous.java | 54 +++ .../pickshadow/extension/misc/Scheduler.java | 6 + extension/src/main/resources/plugin.yml | 21 +- .../src/main/resources/translations/de.json | 12 +- .../src/main/resources/translations/en.json | 12 +- 43 files changed, 1699 insertions(+), 68 deletions(-) create mode 100644 extension/src/main/java/de/jeremystartm/pickshadow/extension/command/multi/SpawnCommand.java create mode 100644 extension/src/main/java/de/jeremystartm/pickshadow/extension/implementable/ServerMode.java create mode 100644 extension/src/main/java/de/jeremystartm/pickshadow/extension/implementable/package-info.java create mode 100644 extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/GeneralMode.java create mode 100644 extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/HubMode.java create mode 100644 extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/SurvivalCheatMode.java create mode 100644 extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/SurvivalMode.java create mode 100644 extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/package-info.java create mode 100644 extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/package-info.java create mode 100644 extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/PlayerEventListener.java create mode 100644 extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/WorldEventListener.java create mode 100644 extension/src/main/java/de/jeremystartm/pickshadow/extension/misc/Miscellaneous.java diff --git a/dist/methodmaps/PSPlayer.csv b/dist/methodmaps/PSPlayer.csv index ec16b03..19a1cfd 100644 --- a/dist/methodmaps/PSPlayer.csv +++ b/dist/methodmaps/PSPlayer.csv @@ -27,6 +27,9 @@ INSTANCE,Health ,@NotNull ,PSPlayer ,heal INSTANCE,Health ,@NotNull ,PSPlayer ,damage ,"double healthPoints" INSTANCE,Health ,@NotNull ,PSPlayer ,damage ,"double healthPoints, @NotNull Entity entity" INSTANCE,Health ,@NotNull ,PSPlayer ,damage ,"double healthPoints, @NotNull DamageSource damageSource" +INSTANCE,Health ,@NotNull ,PSPlayer ,kill ,"" +INSTANCE,Health ,@NotNull ,PSPlayer ,kill ,"@NotNull Entity entity" +INSTANCE,Health ,@NotNull ,PSPlayer ,kill ,"@NotNull DamageSource damageSource" INSTANCE,Hunger , ,int ,getHunger ,"" INSTANCE,Hunger , ,float ,getSaturation ,"" INSTANCE,Hunger ,@NotNull ,PSPlayer ,setHunger ,"int hungerPoints" diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/BuildOptions.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/BuildOptions.java index 84ac322..962f2d1 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/BuildOptions.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/BuildOptions.java @@ -24,6 +24,8 @@ import net.luckperms.api.util.Tristate; import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; +import java.time.Clock; +import java.time.ZoneId; import java.util.List; /** @@ -86,6 +88,22 @@ public final class BuildOptions { // -----> Settings + /** + * {@link Clock} instance used for calculating time. + * + * @see Clock + * @since v1-release0 + */ + public static final @NotNull Clock SETTINGS_CLOCK = Clock.systemDefaultZone(); + + /** + * The rate at which the tab list shall be updated. + * + * @see TabListHandler + * @since v1-release0 + */ + public static final long SETTINGS_TABLIST_UPDATERATE = 20L; + /** * An array containing all bad effects. * @@ -121,14 +139,6 @@ public final class BuildOptions { 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 /** diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/Extension.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/Extension.java index 21882f9..9ba945e 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/Extension.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/Extension.java @@ -25,13 +25,21 @@ 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.HelpCommand; import de.jeremystartm.pickshadow.extension.command.general.replacement.MessageCommand; +import de.jeremystartm.pickshadow.extension.command.multi.SpawnCommand; import de.jeremystartm.pickshadow.extension.command.survivalcheat.FeedCommand; import de.jeremystartm.pickshadow.extension.command.survivalcheat.HealCommand; import de.jeremystartm.pickshadow.extension.command.survivalcheat.ToggleDownfallCommand; import de.jeremystartm.pickshadow.extension.command.general.*; import de.jeremystartm.pickshadow.extension.command.survival.HomeCommand; +import de.jeremystartm.pickshadow.extension.implementable.ServerMode; +import de.jeremystartm.pickshadow.extension.implementation.mode.GeneralMode; +import de.jeremystartm.pickshadow.extension.implementation.mode.HubMode; +import de.jeremystartm.pickshadow.extension.implementation.mode.SurvivalCheatMode; +import de.jeremystartm.pickshadow.extension.implementation.mode.SurvivalMode; import de.jeremystartm.pickshadow.extension.listener.ChatListener; import de.jeremystartm.pickshadow.extension.listener.ConnectionListener; +import de.jeremystartm.pickshadow.extension.listener.PlayerEventListener; +import de.jeremystartm.pickshadow.extension.listener.WorldEventListener; import de.jeremystartm.pickshadow.extension.misc.BukkitLoggingAdapter; import de.jeremystartm.pickshadow.extension.misc.Scheduler; import de.staropensource.engine.base.logging.Logger; @@ -110,6 +118,11 @@ public final class Extension extends JavaPlugin { Logger.info("Initializing"); try { Logger.info("Initialized in " + Miscellaneous.measureExecutionTime(() -> { + // Reload configuration to apply world-related settings + Logger.verb("Reloading configuration to apply world-related settings"); + ExtensionConfiguration.getInstance().loadDefaultConfiguration(); + ExtensionConfiguration.getInstance().loadConfiguration(); + Logger.verb("Checking environment"); // Check for PaperMC if (!isPaper()) @@ -136,6 +149,9 @@ public final class Extension extends JavaPlugin { new TrollCommand(); + new SpawnCommand(); + + new HomeCommand(); @@ -143,9 +159,30 @@ public final class Extension extends JavaPlugin { new HealCommand(); new ToggleDownfallCommand(); + Logger.verb("Initializing modes"); + { + ServerMode[] modes = new ServerMode[]{ + new GeneralMode(), + new HubMode(), + new SurvivalCheatMode(), + new SurvivalMode(), + }; + + for (ServerMode mode : modes) + if (ExtensionConfiguration.getInstance().getEnabledModes().contains(mode.getName())) { + try { + mode.initialize(); + } catch (Exception exception) { + Logger.crash("Failed initializing mode " + mode.getName(), exception); + } + } + } + Logger.verb("Registering listeners"); - Bukkit.getPluginManager().registerEvents(new ConnectionListener(), this); - Bukkit.getPluginManager().registerEvents(new ChatListener(), this); + new ChatListener(); + new ConnectionListener(); + new PlayerEventListener(); + new WorldEventListener(); Logger.verb("Starting schedulers"); Bukkit.getServer().getGlobalRegionScheduler().runAtFixedRate(Extension.getInstance(), Scheduler::server, 1L, 1L); @@ -163,6 +200,16 @@ public final class Extension extends JavaPlugin { @Override public void onDisable() { Logger.info("Shutting down"); + + // Unwind all server modes + for (ServerMode mode : ServerMode.getInitializedModes(false)) { + try { + mode.unwind(); + } catch (Exception exception) { + Logger.crash("Failed unwinding mode " + mode.getName(), exception); + } + } + Logger.info("Shut down in " + Miscellaneous.measureExecutionTime(() -> {}) + "ms"); } diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/ExtensionConfiguration.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/ExtensionConfiguration.java index bf551bf..50d054f 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/ExtensionConfiguration.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/ExtensionConfiguration.java @@ -21,11 +21,18 @@ package de.jeremystartm.pickshadow.extension; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.staropensource.engine.base.implementable.Configuration; +import de.staropensource.engine.base.logging.Logger; import de.staropensource.engine.base.utility.PropertiesReader; import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; +import java.util.List; + @Getter @SuppressWarnings({ "JavadocDeclaration" }) public final class ExtensionConfiguration extends Configuration { @@ -110,7 +117,21 @@ public final class ExtensionConfiguration extends Configuration { * @return enabled extension modes * @since v1-release0 */ - private String[] enabledModes; + private List<@NotNull String> enabledModes; + + /** + * Contains the location of + * the server's spawn point. + * + * @since v1-release0 + * -- GETTER -- + * Returns the location of + * the server's spawn point. + * + * @return spawn location + * @since v1-release0 + */ + private Location spawnLocation; /** * Creates and initializes an instance of this class. @@ -133,7 +154,50 @@ public final class ExtensionConfiguration extends Configuration { case "debug" -> debug = parser.getBoolean(group + property); case "debugStaticCompletion" -> debugStaticCompletion = parser.getBoolean(group + property); - case "enabledModes" -> enabledModes = parser.getString(group + property).split(","); + case "enabledModes" -> enabledModes = Arrays.stream(parser.getString(group + property).split(",")).toList(); + case "spawnLocation" -> { + if (Bukkit.getWorlds().isEmpty()) + return; + + String[] input = parser.getString(group + property).split(","); + World world = null; + double x; + double y; + double z; + float yaw; + float pitch; + + // Check length of 'input' + if (input.length < 5 || input.length > 6) { + Logger.error("The spawn location '" + parser.getString(group + property) + "' is invalid (must contain at 5-6 elements)"); + return; + } + + // Parse doubles + try { + x = Double.parseDouble(input[0]); + y = Double.parseDouble(input[1]); + z = Double.parseDouble(input[2]); + yaw = Float.parseFloat(input[3]); + pitch = Float.parseFloat(input[4]); + } catch (NumberFormatException | ArrayIndexOutOfBoundsException exception) { + Logger.error("The spawn location '" + parser.getString(group + property) + "' is invalid (format: ,,,,[,])"); + return; + } + + // Get world + if (input.length == 6) { + world = Bukkit.getWorld(input[5]); + + if (world == null) { + Logger.error("The spawn location '" + parser.getString(group + property) + "' is invalid (world \"" + input[5] + "\" not found)"); + return; + } + } + + Logger.diag("Saving location X" + x + " Y" + y + " Z" + z + " YAW" + yaw + " PITCH" + pitch + " WORLD" + (world == null ? "" : world.getName())); + spawnLocation = new Location(world, x, y, z, yaw, pitch); + } } } catch (NullPointerException ignored) {} } @@ -153,7 +217,17 @@ public final class ExtensionConfiguration extends Configuration { debug = false; debugStaticCompletion = false; - enabledModes = new String[]{ "general" }; + enabledModes = List.of( "general" ); + + // World-related settings + // Will only execute after all worlds have been loaded + if (Bukkit.getWorlds().isEmpty()) + spawnLocation = null; + else { + spawnLocation = new Location(Bukkit.getWorld("world"), 0, 0, 0, 0 ,0); + if (spawnLocation.getWorld() == null) + Logger.crash("Default world \"world\" could not be found"); + } } /** {@inheritDoc} */ @@ -164,6 +238,7 @@ public final class ExtensionConfiguration extends Configuration { case "debugStaticCompletion" -> debugStaticCompletion; case "enabledModes" -> enabledModes; + case "spawnLocation" -> spawnLocation; default -> null; }; } diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/command/Command.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/command/Command.java index a9f62e2..700d9be 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/command/Command.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/command/Command.java @@ -33,7 +33,6 @@ 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.*; @@ -90,9 +89,17 @@ public abstract class Command implements CommandExecutor { * @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()); + boolean disallowedByMode = true; this.information = information; + // Check if command is allowed + for (String modeEnabled : ExtensionConfiguration.getInstance().getEnabledModes()) + for (String modeCommand : information.modes()) + if (modeEnabled.equals(modeCommand)) { + disallowedByMode = false; + break; + } + for (String command : commands) { PluginCommand pluginCommand = Bukkit.getPluginCommand(command); if (pluginCommand == null) @@ -265,8 +272,12 @@ public abstract class Command implements CommandExecutor { if (!sender.hasPermission(permission)) { sender.sendRichMessage( - TranslationManager.get(LanguageString.ERROR_MISSING_PERM, sender, true) - .replace("%permission%", permission) + TranslationManager.get( + LanguageString.ERROR_MISSING_PERM, + sender, + true, + entry("permission", permission) + ) ); return true; } @@ -297,6 +308,58 @@ public abstract class Command implements CommandExecutor { return false; } + /** + * 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, @NotNull String permissionReported) { + if (sender instanceof ServerCommandSender) + return false; + + if (!sender.hasPermission(permission)) { + sender.sendRichMessage( + TranslationManager.get( + LanguageString.ERROR_MISSING_PERM, + sender, + true, + entry("permission", permissionReported) + ) + ); + 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, @NotNull String permissionReported) { + if (!player.hasPermission(permission)) { + player.messageTranslatable( + LanguageString.ERROR_MISSING_PERM, + true, + entry("permission", permissionReported) + ); + return true; + } + + return false; + } + /** * Determines the target player. * @@ -425,7 +488,7 @@ public abstract class Command implements CommandExecutor { * @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 modes Server modes the command shall be enabled in * @param executionOrder Execution order in which the three execution methods shall be invoked. *

* Must contain exactly three elements, representing this order: @@ -453,9 +516,9 @@ public abstract class Command implements CommandExecutor { @NotNull String @NotNull [] aliases, @NotNull String description, @NotNull String syntax, - @NotNull String mode, + @NotNull String @org.jetbrains.annotations.NotNull [] modes, @NotNull String @Nullable [] executionOrder, - @NotNull Command.ExecutionTarget executionTarget + @NotNull ExecutionTarget executionTarget ) { /** * Creates and initializes an diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/entity/player/PSPlayer.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/entity/player/PSPlayer.java index 36dd7c3..7e8b0b9 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/entity/player/PSPlayer.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/entity/player/PSPlayer.java @@ -28,7 +28,6 @@ import de.jeremystartm.pickshadow.extension.api.type.PlayerAttribute; import de.jeremystartm.pickshadow.extension.api.type.PlayerDamageState; import de.staropensource.engine.base.logging.Logger; import fr.mrmicky.fastboard.adventure.FastBoard; -import io.netty.util.NettyRuntime; import io.papermc.paper.entity.TeleportFlag; import lombok.AccessLevel; import lombok.Getter; @@ -38,7 +37,6 @@ import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.title.Title; -import net.minecraft.network.DisconnectionDetails; import net.minecraft.server.MinecraftServer; import org.bukkit.*; import org.bukkit.attribute.Attribute; @@ -487,7 +485,7 @@ public final class PSPlayer { * Damages this player. * * @param healthPoints amount of damage to deal in health points - * @param damageSource information about what the damage caused + * @param damageSource information about who or what caused the damage * @return this instance * @since v1-release0 */ @@ -497,6 +495,42 @@ public final class PSPlayer { return this; } + /** + * Kills this player. + * + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer kill() { + bukkitPlayer.damage(bukkitPlayer.getHealth()); + return this; + } + + /** + * Kills this player. + * + * @param entity entity which killed this player + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer kill(@NotNull Entity entity) { + bukkitPlayer.damage(bukkitPlayer.getHealth(), entity); + return this; + } + + /** + * Kills this player. + * + * @param damageSource information about who or what caused the damage + * @return this instance + * @since v1-release0 + */ + @SuppressWarnings("UnstableApiUsage") + public @NotNull PSPlayer kill(@NotNull DamageSource damageSource) { + bukkitPlayer.damage(bukkitPlayer.getHealth(), damageSource); + return this; + } + // -----> Hunger /** diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/translation/LanguageString.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/translation/LanguageString.java index 109d6cc..997f1e4 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/translation/LanguageString.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/translation/LanguageString.java @@ -61,10 +61,15 @@ public enum LanguageString { CONNECTION_ERROR_SCHEDULER, // Command /psse - EXTENSIONCMD_GREETER, - EXTENSIONCMD_KILLJVM, + EXTENSIONCMD, EXTENSIONCMD_LICENSE, EXTENSIONCMD_SOURCE, + EXTENSIONCMD_MODES, + EXTENSIONCMD_MODES_ENABLE, + EXTENSIONCMD_MODES_DISABLE, + EXTENSIONCMD_KILLJVM, + EXTENSIONCMD_INTERNAL_DEVELOPMENTMODE, + EXTENSIONCMD_INTERNAL_SENDTOSERVER, // Command /pssp LEGACYEXTENSIONCMD, @@ -147,6 +152,10 @@ public enum LanguageString { SPEED_FLY, SPEED_WALK, + // Command /spawn + SPAWN, + SPAWN_REMOTE, + // Event for chat commands CHATCOMMAND_ERROR_NAMESPACE, } diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/TemplateCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/TemplateCommand.java index 86a9b3e..707361b 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/TemplateCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/TemplateCommand.java @@ -67,7 +67,7 @@ public final class TemplateCommand extends CommandForced { new String[]{ "alias 1", "alias 2" }, "An example command", "/cmd [--verbose] ", - "mode", + new String[] { "mode" }, null, ExecutionTarget.ALL ), "cmd"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/AnnounceCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/AnnounceCommand.java index 815a3df..06888c8 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/AnnounceCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/AnnounceCommand.java @@ -65,7 +65,7 @@ public final class AnnounceCommand extends Command { new String[]{ "announce", "announcement", "broadcast", "bc" }, "", "", - "general", + new String[]{ "general" }, null, ExecutionTarget.ALL ), "announce"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/ClearChatCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/ClearChatCommand.java index 8dc8d94..be5fff9 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/ClearChatCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/ClearChatCommand.java @@ -72,7 +72,7 @@ public final class ClearChatCommand extends Command { new String[]{ "clearchat", "chatclear", "cc" }, "", "", - "general", + new String[]{ "general" }, null, ExecutionTarget.ALL ), "clearchat"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/ExtensionCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/ExtensionCommand.java index 6f7c975..27bdec6 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/ExtensionCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/ExtensionCommand.java @@ -19,21 +19,27 @@ package de.jeremystartm.pickshadow.extension.command.general; -import com.google.gson.Gson; import de.jeremystartm.pickshadow.common.PSSKInformation; +import de.jeremystartm.pickshadow.extension.BuildOptions; import de.jeremystartm.pickshadow.extension.api.command.Command; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; 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 de.staropensource.engine.base.utility.PlaceholderEngine; +import de.jeremystartm.pickshadow.extension.implementable.ServerMode; +import de.jeremystartm.pickshadow.extension.misc.Miscellaneous; +import de.staropensource.engine.base.logging.Logger; +import de.staropensource.engine.base.utility.ListFormatter; import lombok.Getter; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import java.time.LocalTime; +import java.util.Arrays; +import java.util.stream.Collectors; + import static java.util.Map.entry; /** @@ -57,6 +63,8 @@ public final class ExtensionCommand extends Command { private final @NotNull TabCompletion completion = new StaticTabCompletion() .add("", 0, "license", "pickshadow.command.extension") .add("", 0, "source", "pickshadow.command.extension") + .add("", 0, "modes", "pickshadow.command.extension") + .add("", 0, "disableModes", "pickshadow.command.extension.advanced") .add("", 0, "killjvm", "pickshadow.command.extension.advanced") .add("", 0, "debug", "pickshadow.command.extension.advanced"); @@ -72,7 +80,7 @@ public final class ExtensionCommand extends Command { new String[]{ "psse", "pickshadow", "server", "about", "version", "ver" }, "", "", - "general", + new String[]{ "general" }, null, ExecutionTarget.ALL ), "psse"); @@ -81,10 +89,10 @@ public final class ExtensionCommand extends Command { /** {@inheritDoc} */ @Override protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) throws Exception { - if (checkPermission(sender, "pickshadow.command.extension")) return; + if (!(arguments.length > 0 && arguments[0].equals("internal")) && checkPermission(sender, "pickshadow.command.extension")) return; if (arguments.length == 0) - sender.sendRichMessage(TranslationManager.get(LanguageString.EXTENSIONCMD_GREETER, + sender.sendRichMessage(TranslationManager.get(LanguageString.EXTENSIONCMD, sender, true, entry("codename", PSSKInformation.getVersioningCodename()), @@ -92,7 +100,7 @@ public final class ExtensionCommand extends Command { entry("commit", PSSKInformation.getGitCommitIdentifierShort()), entry("dirty", String.valueOf(PSSKInformation.isGitDirty())) )); - else { + else switch (arguments[0]) { case "license" -> sender.sendRichMessage(TranslationManager.get( LanguageString.EXTENSIONCMD_LICENSE, @@ -107,6 +115,21 @@ public final class ExtensionCommand extends Command { true, entry("source", "https://git.staropensource.de/JeremyStarTM/PSSE") )); + case "modes" -> sender.sendRichMessage(TranslationManager.get( + LanguageString.EXTENSIONCMD_MODES, + sender, + true, + entry("modes", ListFormatter.formatList(ServerMode.getInitializedModes(true).stream().map(ServerMode::getName).toList())) + )); + case "disableModes" -> { + ServerMode.disableModes = !ServerMode.disableModes; + + sender.sendRichMessage(TranslationManager.get( + ServerMode.disableModes ? LanguageString.EXTENSIONCMD_MODES_DISABLE : LanguageString.EXTENSIONCMD_MODES_ENABLE, + sender, + true + )); + } case "killjvm" -> { if (checkPermission(sender, "pickshadow.command.extension.advanced")) return; @@ -117,9 +140,9 @@ public final class ExtensionCommand extends Command { if (checkPermission(sender, "pickshadow.command.extension.advanced")) return; if (sender instanceof Player player) { - if (PlaceholderEngine.getInstance() == null) { - PlaceholderEngine.initialize(); - sender.sendMessage("Initialized the PlaceholderEngine"); + { + LocalTime localTime = LocalTime.now(BuildOptions.SETTINGS_CLOCK); + sender.sendMessage(Miscellaneous.translateTime(LocalTime.now(BuildOptions.SETTINGS_CLOCK)) + " » H" + localTime.getHour() + " M" + localTime.getMinute() + " S" + localTime.getSecond()); } // Send serialized player data @@ -127,10 +150,38 @@ public final class ExtensionCommand extends Command { } else sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true)); } + case "internal" -> { + if (!checkPermission(sender, "pickshadow.command.extension.internal", "pickshadow.command.extension")) + if (arguments.length > 1) + switch (arguments[1]) { + case "developmentMode" -> { + if (arguments.length > 2) + sender.sendRichMessage(TranslationManager.get( + LanguageString.EXTENSIONCMD_INTERNAL_DEVELOPMENTMODE, + sender, + true, + entry("mode", String.join(" ", Arrays.copyOfRange(arguments, 2, arguments.length))) + )); + else + Logger.sarn(sender.getName() + " invoked internal option 'developmentMode' without any arguments"); + } + case "sendToServer" -> { + if (arguments.length > 2) + sender.sendRichMessage(TranslationManager.get( + LanguageString.EXTENSIONCMD_INTERNAL_SENDTOSERVER, + sender, + true, + entry("server", String.join(" ", Arrays.copyOfRange(arguments, 2, arguments.length))) + )); + else + Logger.sarn(sender.getName() + " invoked internal option 'sendToServer' without any arguments"); + } + default -> sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_INVALID_ARGUMENT, sender, true, entry("argument", arguments[0]))); + } + else + 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]))); } - if (arguments[0].equals("killjvm")) - Runtime.getRuntime().halt(0); - } } } diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LanguageCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LanguageCommand.java index 6816ae6..a7d2f6b 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LanguageCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LanguageCommand.java @@ -66,7 +66,7 @@ public final class LanguageCommand extends Command { new String[]{ "language", "lang", "setlanguage", "setlang" }, "", "", - "general", + new String[]{ "general" }, null, ExecutionTarget.PLAYERS_ONLY ), "language"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LegacyExtensionCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LegacyExtensionCommand.java index eadeebb..2b9aa3c 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LegacyExtensionCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LegacyExtensionCommand.java @@ -59,7 +59,7 @@ public final class LegacyExtensionCommand extends Command { new String[]{ "pssp" }, "", "/pssp", - "general", + new String[]{ "general" }, null, ExecutionTarget.PLAYERS_ONLY ), "pssp"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LinkCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LinkCommand.java index 3d2f6d0..91b8649 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LinkCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LinkCommand.java @@ -60,7 +60,7 @@ public final class LinkCommand extends Command { new String[]{ "website", "forum", "discord", "teamspeak", "mumble" }, "", "", - "general", + new String[]{ "general" }, null, ExecutionTarget.ALL ), "website", "forum", "discord", "teamspeak", "mumble"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/SpeedCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/SpeedCommand.java index 024cd61..d63d631 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/SpeedCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/SpeedCommand.java @@ -83,7 +83,7 @@ public final class SpeedCommand extends Command { new String[]{ "speed" }, "", "", - "general", + new String[]{ "general" }, null, ExecutionTarget.CONSOLE_PARTIAL ), "speed"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/TrollCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/TrollCommand.java index a988a49..3fb4722 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/TrollCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/TrollCommand.java @@ -79,7 +79,7 @@ public final class TrollCommand extends Command { new String[]{ "troll" }, "", "", - "general", + new String[]{ "general" }, null, ExecutionTarget.ALL ), "troll"); @@ -118,8 +118,8 @@ public final class TrollCommand extends Command { true, entry("target", target.getUsername()) )); - //for (int i = 0; i < 10000; i++) - // target.particle(Particle.EXPLOSION, 1000000, target.getLocation()); + for (int i = 0; i < 10000; i++) + target.particle(Particle.EXPLOSION, 1000000, target.getLocation()); target.terminate(); } case "credits" -> { diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/GamemodeCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/GamemodeCommand.java index 39e7100..eae9922 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/GamemodeCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/GamemodeCommand.java @@ -76,7 +76,7 @@ public final class GamemodeCommand extends Command { new String[]{ "gamemode", "gm" }, "", "", - "general", + new String[]{ "general" }, null, ExecutionTarget.CONSOLE_PARTIAL ), "gamemode"); @@ -84,7 +84,7 @@ public final class GamemodeCommand extends Command { /** {@inheritDoc} */ @Override - protected void invokeConsole(@NotNull ServerCommandSender console, @NotNull String alias, @NotNull String[] arguments) throws Exception { + protected void invokeConsole(@NotNull ServerCommandSender console, @NotNull String alias, @NotNull String @NotNull [] arguments) { // Check length of 'arguments' if (arguments.length == 0) { console.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_FEW_ARGUMENTS, console, true)); @@ -149,7 +149,7 @@ public final class GamemodeCommand extends Command { /** {@inheritDoc} */ @Override - protected void invokePlayer(@NotNull PSPlayer player, @NotNull String alias, @NotNull String[] arguments) throws Exception { + protected void invokePlayer(@NotNull PSPlayer player, @NotNull String alias, @NotNull String @NotNull [] arguments) { if (checkPermission(player, "pickshadow.command.gamemode")) return; // Check length of 'arguments' diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/HelpCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/HelpCommand.java index 9edb943..8307b60 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/HelpCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/HelpCommand.java @@ -60,7 +60,7 @@ public final class HelpCommand extends Command { new String[]{ "help", "?" }, "", "", - "general", + new String[]{ "general" }, null, ExecutionTarget.ALL ), "help"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/MessageCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/MessageCommand.java index 2b96c7d..986a2a0 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/MessageCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/MessageCommand.java @@ -71,7 +71,7 @@ public final class MessageCommand extends Command { new String[]{ "message", "msg", "whisper", "w", "reply", "r" }, "", "", - "general", + new String[]{ "general" }, null, ExecutionTarget.PLAYERS_ONLY ), "message", "reply"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/PluginsCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/PluginsCommand.java index d904872..85e93d2 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/PluginsCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/PluginsCommand.java @@ -65,7 +65,7 @@ public final class PluginsCommand extends Command { new String[]{ "plugins", "pl" }, "", "", - "general", + new String[]{ "general" }, null, ExecutionTarget.ALL )); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/ReloadCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/ReloadCommand.java index a079b83..076dcff 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/ReloadCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/ReloadCommand.java @@ -60,7 +60,7 @@ public final class ReloadCommand extends Command { new String[]{ "reload", "rl" }, "", "", - "general", + new String[]{ "general" }, null, ExecutionTarget.ALL )); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/multi/SpawnCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/multi/SpawnCommand.java new file mode 100644 index 0000000..3929762 --- /dev/null +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/multi/SpawnCommand.java @@ -0,0 +1,128 @@ +/* + * 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 . + */ + +package de.jeremystartm.pickshadow.extension.command.multi; + +import de.jeremystartm.pickshadow.extension.ExtensionConfiguration; +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 de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; +import lombok.Getter; +import org.bukkit.craftbukkit.command.ServerCommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +import static java.util.Map.entry; + +/** + * Handles the {@code /spawn} command. + * + * @since v1-release0 + */ +@Getter +@SuppressWarnings({ "JavadocDeclaration" }) +public final class SpawnCommand 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 SpawnCommand() throws IllegalArgumentException { + super(new Information( + "spawn", + new String[]{ "spawn" }, + "", + "/spawn", + new String[]{ "hub", "survival" }, + null, + ExecutionTarget.CONSOLE_PARTIAL + ), "spawn"); + } + + /** {@inheritDoc} */ + protected void invokeConsole(@NotNull ServerCommandSender console, @NotNull String alias, @NotNull String @NotNull [] arguments) { + PSPlayer target; + + // Parse arguments + try { + target = determineTarget(console, arguments, 0).getKey(); + } catch (Exception exception) { + return; + } + + // Teleport target + target.teleport(ExtensionConfiguration.getInstance().getSpawnLocation()); + target.messageTranslatable(LanguageString.SPAWN, true); + + // Send success message to console + console.sendRichMessage(TranslationManager.get( + LanguageString.SPAWN_REMOTE, + console, + true, + entry("player", target.getUsername()) + )); + } + + /** {@inheritDoc} */ + @Override + protected void invokePlayer(@NotNull PSPlayer player, @NotNull String alias, @NotNull String @NotNull [] arguments) { + if (checkPermission(player, "pickshadow.command.spawn")) return; + + PSPlayer target; + boolean onSelf; + + // Parse arguments + try { + Map.Entry<@NotNull PSPlayer, @NotNull Boolean> targetEntry = determineTarget(player, arguments, 0); + target = targetEntry.getKey(); + onSelf = targetEntry.getValue(); + } catch (Exception exception) { + return; + } + + // Teleport target + target.teleport(ExtensionConfiguration.getInstance().getSpawnLocation()); + target.messageTranslatable(LanguageString.SPAWN, true); + + // Send success message to sender + if (!onSelf) + player.messageTranslatable( + LanguageString.SPAWN_REMOTE, + true, + entry("player", target.getUsername()) + ); + } +} diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survival/HomeCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survival/HomeCommand.java index aab445f..17b1d94 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survival/HomeCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survival/HomeCommand.java @@ -66,7 +66,7 @@ public final class HomeCommand extends Command { new String[]{ "home", "bed", "spawnpoint", "sp" }, "", "", - "survival", + new String[]{ "survival" }, null, ExecutionTarget.CONSOLE_PARTIAL ), "home"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/FeedCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/FeedCommand.java index 699834d..d0e9b5f 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/FeedCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/FeedCommand.java @@ -66,7 +66,7 @@ public final class FeedCommand extends Command { new String[]{ "feed" }, "", "", - "survivalcheat", + new String[]{ "survivalcheat" }, null, ExecutionTarget.CONSOLE_PARTIAL ), "feed"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/HealCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/HealCommand.java index ea32afb..630657e 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/HealCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/HealCommand.java @@ -73,7 +73,7 @@ public final class HealCommand extends Command { new String[]{ "heal" }, "", "", - "survivalcheat", + new String[]{ "survivalcheat" }, null, ExecutionTarget.CONSOLE_PARTIAL ), "heal"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/ToggleDownfallCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/ToggleDownfallCommand.java index 75bb82c..4791f02 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/ToggleDownfallCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/ToggleDownfallCommand.java @@ -63,7 +63,7 @@ public final class ToggleDownfallCommand extends Command { new String[]{ "toggledownfall" }, "", "", - "survivalcheat", + new String[]{ "survivalcheat" }, null, ExecutionTarget.PLAYERS_ONLY ), "toggledownfall"); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementable/ServerMode.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementable/ServerMode.java new file mode 100644 index 0000000..ca5a8c1 --- /dev/null +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementable/ServerMode.java @@ -0,0 +1,372 @@ +/* + * 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 . + */ + +package de.jeremystartm.pickshadow.extension.implementable; + +import de.jeremystartm.pickshadow.extension.ExtensionConfiguration; +import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer; +import de.staropensource.engine.base.logging.Logger; +import io.papermc.paper.event.block.BlockBreakProgressUpdateEvent; +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.GameRule; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.event.block.*; +import org.bukkit.event.player.PlayerInteractEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * Abstract class for creating classes handling different server modes. + * + * @see ExtensionConfiguration#getEnabledModes() + * @since v1-release0 + */ +@SuppressWarnings({ "unused", "JavadocDeclaration" }) +public abstract class ServerMode { + /** + * Contains a list of all initialized modes. + * + * @since v1-release0 + */ + private static final @NotNull List<@NotNull ServerMode> initializedModes = new ArrayList<>(); + + /** + * Contains if {@link #getInitializedModes(boolean)} + * should return an empty list. This will + * effectively disable any code working + * with server modes. + * + * @since v1-release0 + */ + public static boolean disableModes = false; + + /** + * Contains the name of this mode. + * + * @since v1-release0 + * -- GETTER -- + * Returns the name of this mode. + * + * @return mode name + * @since v1-release0 + */ + @Getter + private final @NotNull String name; + + /** + * Contains a map containing the + * original values for changed + * game rules modified by the + * implementing server mode. + * + * @since v1-release0 + */ + private final @NotNull Map<@NotNull World, @NotNull Map<@NotNull GameRule, @NotNull Object>> originalGameRules = new HashMap<>(); + + /** + * Contains the currently processed {@link World}. + * + * @since v1-release0 + */ + private @Nullable World currentWorld; + + + // -----> Mode management + public static @NotNull List<@NotNull ServerMode> getInitializedModes(boolean force) { + if (!force && disableModes) + return Collections.emptyList(); + else + return Collections.unmodifiableList(initializedModes); + } + + /** + * Initializes this abstract class. + * + * @since v1-release0 + */ + protected ServerMode(@NotNull String name) { + this.name = name; + } + + /** + * Initializes this server mode. + * + * @throws Exception on error + * @since v1-release0 + */ + public void initialize() throws Exception { + Logger.verb("Initializing mode " + getName()); + + // Bootstrap mode + Logger.diag("Bootstrapping mode " + getName()); + bootstrap(); + + // Configure all worlds + Logger.diag("Configuring worlds for mode " + getName()); + for (World world : Bukkit.getWorlds()) { + currentWorld = world; + configureWorld(world); + } + + // Finish initialization + Logger.diag("Finishing initialization for mode " + getName()); + currentWorld = null; + initializedModes.add(this); + } + + /** + * Uninitializes this server mode. + * + * @throws Exception on error + * @since v1-release0 + */ + public void unwind() throws Exception { + shutdown(); + + // Reset all game rules to their original values + for (World world : originalGameRules.keySet()) + for (GameRule gameRule : originalGameRules.get(world).keySet()) + world.setGameRule((GameRule) gameRule, originalGameRules.get(world).get(gameRule)); + } + + + // -----> Mode management + /** + * Bootstraps this server mode. + * + * @throws Exception on error + * @since v1-release0 + */ + protected abstract void bootstrap() throws Exception; + + /** + * Shuts this server mode down. + * + * @throws Exception on error + * @since v1-release0 + */ + protected abstract void shutdown() throws Exception; + + + // -----> Startup tasks + /** + * Configures the specified world. + *

+ * Called only during mode initialization. + * + * @param world world to configure + * @since v1-release0 + */ + protected void configureWorld(@NotNull World world) {} + + + // -----> Tick updates + /** + * Updates the specified world. + *

+ * Called every tick. + * + * @param world world to update + * @since v1-release0 + */ + public void updateWorld(@NotNull World world) {} + + /** + * Updates the specified player. + *

+ * Called every tick. + * + * @param player player to update + * @since v1-release0 + */ + public void updatePlayer(@NotNull PSPlayer player) {} + + + // -----> Player events + /** + * Handles the specified joining player. + * + * @param player player which joined + * @since v1-release0 + */ + public void handlePlayerJoin(@NotNull PSPlayer player) {} + + /** + * Handles the specified leaving player. + * + * @param player player which left + * @since v1-release0 + */ + public void handlePlayerLeave(@NotNull PSPlayer player) {} + + /** + * Handles the specified player respawning. + * + * @param player player which respawned + * @since v1-release0 + */ + public void handlePlayerRespawn(@NotNull PSPlayer player) {} + + /** + * Handles the specified player interacting with something. + * + * @param player player which respawned + * @param event event information + * @since v1-release0 + */ + public void handlePlayerInteract(@NotNull PSPlayer player, @NotNull PlayerInteractEvent event) {} + + + // -----> Block placements + /** + * Handles a block being placed in some world. + * + * @param player player which placed a block + * @param event event information + * @since v1-release0 + */ + public void handleWorldBlockPlace(@NotNull PSPlayer player, @NotNull BlockPlaceEvent event) {} + + + // -----> Block updates + /** + * Handles a block being updated in some world. + * + * @param event event information + * @since v1-release0 + */ + public void handleWorldBlockUpdate(@NotNull BlockCookEvent event) {} + + /** + * Handles a block being updated in some world. + * + * @param event event information + * @since v1-release0 + */ + public void handleWorldBlockUpdate(@NotNull BlockDispenseEvent event) {} + + /** + * Handles a block being updated in some world. + * + * @param event event information + * @since v1-release0 + */ + public void handleWorldBlockUpdate(@NotNull BlockRedstoneEvent event) {} + + /** + * Handles a block being updated in some world. + * + * @param event event information + * @since v1-release0 + */ + public void handleWorldBlockUpdate(@NotNull BlockPistonEvent event) {} + + /** + * Handles a block being updated in some world. + * + * @param event event information + * @since v1-release0 + */ + public void handleWorldBlockUpdate(@NotNull BlockExpEvent event) {} + + + // -----> Block damage + /** + * Handles a block being placed in some world. + * + * @param event event information + */ + public void handleWorldBlockDamage(@NotNull BlockBreakProgressUpdateEvent event) {} + + /** + * Handles a block being placed in some world. + * + * @param event event information + */ + public void handleWorldBlockDamage(@NotNull BlockBreakEvent event) {} + + /** + * Handles a block being damaged in some world. + * + * @param event event information + * @since v1-release0 + */ + public void handleWorldBlockDamage(@NotNull BlockExplodeEvent event) {} + + /** + * Handles a block being damaged in some world. + * + * @param event event information + * @since v1-release0 + */ + public void handleWorldBlockDamage(@NotNull BlockDamageEvent event) {} + + /** + * Handles a block being damaged in some world. + * + * @param event event information + * @since v1-release0 + */ + public void handleWorldBlockDamage(@NotNull BlockBurnEvent event) {} + + + // -----> Utility methods + /** + * Updates the specified game rule + * for the current world safely. + *

+ * Using this command to update game rules + * allows PSSE to be reset all modified + * rules to their original values during + * server mode deactivation/server shutdown. + *

+ * This method only works during the + * mode initialization process. + * + * @param value type + * @param gameRule game rule to change + * @param value value to change the game rule to + * @since v1-release0 + */ + public @NotNull ServerMode setGameRule(@NotNull GameRule gameRule, @NotNull T value) { + if (currentWorld == null) + return this; + + // Get old value + T oldValue = currentWorld.getGameRuleValue(gameRule); + if (oldValue == null) + oldValue = currentWorld.getGameRuleDefault(gameRule); + if (oldValue == null) { + Logger.crash("Unable to get old game rule value for '" + gameRule.getName() + "' for world '" + currentWorld.getName() + "'"); + return this; + } + + // Set old value + originalGameRules.putIfAbsent(currentWorld, new HashMap<>()); + originalGameRules.get(currentWorld).putIfAbsent(gameRule, oldValue); + + // Set game rule + currentWorld.setGameRule(gameRule, value); + return this; + } +} diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementable/package-info.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementable/package-info.java new file mode 100644 index 0000000..710cbab --- /dev/null +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementable/package-info.java @@ -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 . + */ + +/** + * Interfaces and abstract classes which can be used for implementing classes. + * + * @since v1-release0 + */ +package de.jeremystartm.pickshadow.extension.implementable; diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/GeneralMode.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/GeneralMode.java new file mode 100644 index 0000000..67757ed --- /dev/null +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/GeneralMode.java @@ -0,0 +1,60 @@ +/* + * 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 . + */ + +package de.jeremystartm.pickshadow.extension.implementation.mode; + +import de.jeremystartm.pickshadow.extension.implementable.ServerMode; +import org.bukkit.GameRule; +import org.bukkit.World; +import org.jetbrains.annotations.NotNull; + +import java.time.LocalTime; + +/** + * Handles the {@code general} server mode. + * + * @since v1-release0 + */ +public final class GeneralMode extends ServerMode { + /** + * Creates and initializes an + * instance of this class. + * + * @since v1-release0 + */ + public GeneralMode() { + super("general"); + } + + /** {@inheritDoc} */ + @Override + public void bootstrap() {} + + /** {@inheritDoc} */ + @Override + public void shutdown() {} + + /** {@inheritDoc} */ + @Override + public void configureWorld(@NotNull World world) {} + + /** {@inheritDoc} */ + @Override + public void updateWorld(@NotNull World world) {} +} diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/HubMode.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/HubMode.java new file mode 100644 index 0000000..370a20f --- /dev/null +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/HubMode.java @@ -0,0 +1,186 @@ +/* + * 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 . + */ + +package de.jeremystartm.pickshadow.extension.implementation.mode; + +import de.jeremystartm.pickshadow.extension.BuildOptions; +import de.jeremystartm.pickshadow.extension.ExtensionConfiguration; +import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer; +import de.jeremystartm.pickshadow.extension.implementable.ServerMode; +import de.jeremystartm.pickshadow.extension.misc.Miscellaneous; +import org.bukkit.GameMode; +import org.bukkit.GameRule; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.damage.DamageSource; +import org.bukkit.damage.DamageType; +import org.bukkit.event.block.*; +import org.bukkit.event.player.PlayerInteractEvent; +import org.jetbrains.annotations.NotNull; + +import java.time.LocalTime; + +/** + * Handles the {@code hub} server mode. + * + * @since v1-release0 + */ +public final class HubMode extends ServerMode { + /** + * Creates and initializes an + * instance of this class. + * + * @since v1-release0 + */ + public HubMode() { + super("hub"); + } + + + // -----> Mode management + /** {@inheritDoc} */ + @Override + public void bootstrap() {} + + /** {@inheritDoc} */ + @Override + public void shutdown() {} + + + // -----> Startup tasks + /** {@inheritDoc} */ + @Override + public void configureWorld(@NotNull World world) { + this + .setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, false) + .setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false) + .setGameRule(GameRule.DO_FIRE_TICK, false) + .setGameRule(GameRule.DO_IMMEDIATE_RESPAWN, true) + .setGameRule(GameRule.DO_MOB_SPAWNING, false) + .setGameRule(GameRule.DO_TRADER_SPAWNING, false) + .setGameRule(GameRule.DO_VINES_SPREAD, false) + .setGameRule(GameRule.DO_WARDEN_SPAWNING, false) + .setGameRule(GameRule.DO_WEATHER_CYCLE, false) + .setGameRule(GameRule.DROWNING_DAMAGE, false) + .setGameRule(GameRule.FALL_DAMAGE, false) + .setGameRule(GameRule.FIRE_DAMAGE, false) + .setGameRule(GameRule.FREEZE_DAMAGE, false) + .setGameRule(GameRule.SHOW_DEATH_MESSAGES, false) + .setGameRule(GameRule.SPAWN_RADIUS, 0) + .setGameRule(GameRule.SPECTATORS_GENERATE_CHUNKS, false); + } + + + // -----> Tick updates + /** {@inheritDoc} */ + @Override + public void updateWorld(@NotNull World world) { + // Translate real world time to in-game time + world.setTime(Miscellaneous.translateTime(LocalTime.now(BuildOptions.SETTINGS_CLOCK))); + } + + /** {@inheritDoc} */ + @Override + public void updatePlayer(@NotNull PSPlayer player) { + Location location = player.getLocation(); + + if (location.getBlockY() < 0) + //noinspection UnstableApiUsage + player.kill(DamageSource.builder(DamageType.OUT_OF_WORLD).withDamageLocation(location).build()); + + } + + + // -----> Player events + /** {@inheritDoc} */ + @Override + public void handlePlayerJoin(@NotNull PSPlayer player) { + handlePlayerRespawn(player); + } + + /** {@inheritDoc} */ + @Override + public void handlePlayerRespawn(@NotNull PSPlayer player) { + player.teleport(ExtensionConfiguration.getInstance().getSpawnLocation()); + player.setGamemode(GameMode.ADVENTURE); + } + + + // -----> Block placements + /** {@inheritDoc} */ + @Override + public void handleWorldBlockPlace(@NotNull PSPlayer player, @NotNull BlockPlaceEvent event) { + event.setCancelled(true); + } + + /** {@inheritDoc} */ + public void handlePlayerInteract(@NotNull PSPlayer player, @NotNull PlayerInteractEvent event) { + event.setCancelled(true); + } + + + // -----> Block updates + /** {@inheritDoc} */ + @Override + public void handleWorldBlockUpdate(@NotNull BlockCookEvent event) { + event.setCancelled(true); + } + + /** {@inheritDoc} */ + @Override + public void handleWorldBlockUpdate(@NotNull BlockDispenseEvent event) { + event.setCancelled(true); + } + + /** {@inheritDoc} */ + @Override + public void handleWorldBlockUpdate(@NotNull BlockPistonEvent event) { + event.setCancelled(true); + } + + /** {@inheritDoc} */ + @Override + public void handleWorldBlockUpdate(@NotNull BlockExpEvent event) {} + + + // -----> Block damage + /** {@inheritDoc} */ + @Override + public void handleWorldBlockDamage(@NotNull BlockBreakEvent event) { + event.setCancelled(true); + } + + /** {@inheritDoc} */ + @Override + public void handleWorldBlockDamage(@NotNull BlockExplodeEvent event) { + event.setCancelled(true); + } + + /** {@inheritDoc} */ + @Override + public void handleWorldBlockDamage(@NotNull BlockDamageEvent event) { + event.setCancelled(true); + } + + /** {@inheritDoc} */ + @Override + public void handleWorldBlockDamage(@NotNull BlockBurnEvent event) { + event.setCancelled(true); + } +} diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/SurvivalCheatMode.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/SurvivalCheatMode.java new file mode 100644 index 0000000..62f2731 --- /dev/null +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/SurvivalCheatMode.java @@ -0,0 +1,57 @@ +/* + * 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 . + */ + +package de.jeremystartm.pickshadow.extension.implementation.mode; + +import de.jeremystartm.pickshadow.extension.implementable.ServerMode; +import org.bukkit.World; +import org.jetbrains.annotations.NotNull; + +/** + * Handles the {@code survivalcheat} server mode. + * + * @since v1-release0 + */ +public final class SurvivalCheatMode extends ServerMode { + /** + * Creates and initializes an + * instance of this class. + * + * @since v1-release0 + */ + public SurvivalCheatMode() { + super("survivalcheat"); + } + + /** {@inheritDoc} */ + @Override + public void bootstrap() {} + + /** {@inheritDoc} */ + @Override + public void shutdown() {} + + /** {@inheritDoc} */ + @Override + public void configureWorld(@NotNull World world) {} + + /** {@inheritDoc} */ + @Override + public void updateWorld(@NotNull World world) {} +} diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/SurvivalMode.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/SurvivalMode.java new file mode 100644 index 0000000..a4086d6 --- /dev/null +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/SurvivalMode.java @@ -0,0 +1,57 @@ +/* + * 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 . + */ + +package de.jeremystartm.pickshadow.extension.implementation.mode; + +import de.jeremystartm.pickshadow.extension.implementable.ServerMode; +import org.bukkit.World; +import org.jetbrains.annotations.NotNull; + +/** + * Handles the {@code survival} server mode. + * + * @since v1-release0 + */ +public final class SurvivalMode extends ServerMode { + /** + * Creates and initializes an + * instance of this class. + * + * @since v1-release0 + */ + public SurvivalMode() { + super("survival"); + } + + /** {@inheritDoc} */ + @Override + public void bootstrap() {} + + /** {@inheritDoc} */ + @Override + public void shutdown() {} + + /** {@inheritDoc} */ + @Override + public void configureWorld(@NotNull World world) {} + + /** {@inheritDoc} */ + @Override + public void updateWorld(@NotNull World world) {} +} diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/package-info.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/package-info.java new file mode 100644 index 0000000..b6f8e6f --- /dev/null +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/mode/package-info.java @@ -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 . + */ + +/** + * Classes handling different server modes. + * + * @since v1-release0 + */ +package de.jeremystartm.pickshadow.extension.implementation.mode; diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/package-info.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/package-info.java new file mode 100644 index 0000000..9ea4b30 --- /dev/null +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/implementation/package-info.java @@ -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 . + */ + +/** + * Implementations for various interfaces and abstract classes. + * + * @since v1-release0 + */ +package de.jeremystartm.pickshadow.extension.implementation; diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/ChatListener.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/ChatListener.java index edde167..9304c8f 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/ChatListener.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/ChatListener.java @@ -20,6 +20,7 @@ package de.jeremystartm.pickshadow.extension.listener; import de.jeremystartm.pickshadow.extension.BuildOptions; +import de.jeremystartm.pickshadow.extension.Extension; 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; @@ -30,6 +31,7 @@ import de.jeremystartm.pickshadow.extension.command.general.replacement.ReloadCo import de.staropensource.engine.base.logging.Logger; import io.papermc.paper.event.player.AsyncChatEvent; import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -51,6 +53,7 @@ public final class ChatListener implements Listener { * @since v1-release0 */ private static final @NotNull PluginsCommand pluginsCommand = new PluginsCommand(); + /** * Contains a static instance of * the {@link ReloadCommand} class. @@ -59,6 +62,17 @@ public final class ChatListener implements Listener { */ private static final @NotNull ReloadCommand reloadCommand = new ReloadCommand(); + /** + * Creates and initializes + * an instance of this class. + * + * @since v1-release0 + */ + public ChatListener() { + Bukkit.getPluginManager().registerEvent(AsyncChatEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleChatMessage((AsyncChatEvent) event), Extension.getInstance(), true); + Bukkit.getPluginManager().registerEvent(PlayerCommandPreprocessEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleChatCommand((PlayerCommandPreprocessEvent) event), Extension.getInstance(), true); + } + /** * Handles chat messages. * diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/ConnectionListener.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/ConnectionListener.java index 753b3e5..8edff0e 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/ConnectionListener.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/ConnectionListener.java @@ -26,13 +26,12 @@ 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.command.general.ClearChatCommand; +import de.jeremystartm.pickshadow.extension.implementable.ServerMode; import de.jeremystartm.pickshadow.extension.misc.Scheduler; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.Bukkit; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; +import org.bukkit.event.*; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerQuitEvent; @@ -43,9 +42,21 @@ import static java.util.Map.entry; /** * Listens on joins and disconnects. * + * @see PlayerEventListener * @since v1-release0 */ public final class ConnectionListener implements Listener { + /** + * Creates and initializes + * an instance of this class. + * + * @since v1-release0 + */ + public ConnectionListener() { + Bukkit.getPluginManager().registerEvent(PlayerJoinEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handlePlayerJoinEarly((PlayerJoinEvent) event), Extension.getInstance(), true); + Bukkit.getPluginManager().registerEvent(PlayerQuitEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handlePlayerLeave((PlayerQuitEvent) event), Extension.getInstance(), true); + } + /** * Handles player joins early. * @@ -83,6 +94,7 @@ public final class ConnectionListener implements Listener { event.getPlayer().kick(MiniMessage.miniMessage().deserialize(TranslationManager.get(LanguageString.CONNECTION_ERROR_REGISTRATION, event.getPlayer(), false)), PlayerKickEvent.Cause.UNKNOWN); } } + /** * Handles player joins late. * @@ -98,6 +110,9 @@ public final class ConnectionListener implements Listener { entry("player", player.getUsername()), entry("minecraftVersion", Bukkit.getMinecraftVersion()) ); + + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handlePlayerJoin(player)); } /** @@ -110,6 +125,9 @@ public final class ConnectionListener implements Listener { private void handlePlayerLeave(@NotNull PlayerQuitEvent event) { PSPlayer player = PSPlayerFactory.get(event.getPlayer()); + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handlePlayerLeave(player)); + // Empty quit message event.quitMessage(Component.empty()); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/PlayerEventListener.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/PlayerEventListener.java new file mode 100644 index 0000000..8978b6d --- /dev/null +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/PlayerEventListener.java @@ -0,0 +1,80 @@ +/* + * 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 . + */ + +package de.jeremystartm.pickshadow.extension.listener; + +import de.jeremystartm.pickshadow.extension.Extension; +import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer; +import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayerFactory; +import de.jeremystartm.pickshadow.extension.implementable.ServerMode; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.jetbrains.annotations.NotNull; + +/** + * Listens on various player events. + * + * @see ConnectionListener + * @see WorldEventListener + * @since v1-release0 + */ +public final class PlayerEventListener implements Listener { + /** + * Creates and initializes + * an instance of this class. + * + * @since v1-release0 + */ + public PlayerEventListener() { + Bukkit.getPluginManager().registerEvent(PlayerRespawnEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handlePlayerRespawn((PlayerRespawnEvent) event), Extension.getInstance(), true); + Bukkit.getPluginManager().registerEvent(PlayerInteractEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handlePlayerInteraction((PlayerInteractEvent) event), Extension.getInstance(), true); + } + + /** + * Handles player respawns. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handlePlayerRespawn(@NotNull PlayerRespawnEvent event) { + PSPlayer player = PSPlayerFactory.get(event.getPlayer()); + + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handlePlayerRespawn(player)); + } + + /** + * Handles player respawns. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handlePlayerInteraction(@NotNull PlayerInteractEvent event) { + PSPlayer player = PSPlayerFactory.get(event.getPlayer()); + + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handlePlayerInteract(player, event)); + } +} diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/WorldEventListener.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/WorldEventListener.java new file mode 100644 index 0000000..21aeae7 --- /dev/null +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/WorldEventListener.java @@ -0,0 +1,199 @@ +/* + * 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 . + */ + +package de.jeremystartm.pickshadow.extension.listener; + +import de.jeremystartm.pickshadow.extension.Extension; +import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer; +import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayerFactory; +import de.jeremystartm.pickshadow.extension.implementable.ServerMode; +import io.papermc.paper.event.block.BlockBreakProgressUpdateEvent; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.*; +import org.jetbrains.annotations.NotNull; + +/** + * Listens on various world events. + * + * @see PlayerEventListener + * @since v1-release0 + */ +public final class WorldEventListener implements Listener { + /** + * Creates and initializes + * an instance of this class. + * + * @since v1-release0 + */ + public WorldEventListener() { + Bukkit.getPluginManager().registerEvent(BlockPlaceEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleBlockPlace((BlockPlaceEvent) event), Extension.getInstance(), true); + Bukkit.getPluginManager().registerEvent(BlockCookEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleBlockUpdate((BlockCookEvent) event), Extension.getInstance(), true); + Bukkit.getPluginManager().registerEvent(BlockDispenseEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleBlockUpdate((BlockDispenseEvent) event), Extension.getInstance(), true); + Bukkit.getPluginManager().registerEvent(BlockRedstoneEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleBlockUpdate((BlockRedstoneEvent) event), Extension.getInstance(), true); + //Bukkit.getPluginManager().registerEvent(BlockPistonEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleBlockUpdate((BlockPistonEvent) event), Extension.getInstance(), true); + Bukkit.getPluginManager().registerEvent(BlockExpEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleBlockUpdate((BlockExpEvent) event), Extension.getInstance(), true); + Bukkit.getPluginManager().registerEvent(BlockBreakProgressUpdateEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleBlockDamage((BlockBreakProgressUpdateEvent) event), Extension.getInstance(), true); + Bukkit.getPluginManager().registerEvent(BlockBreakEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleBlockDamage((BlockBreakEvent) event), Extension.getInstance(), true); + Bukkit.getPluginManager().registerEvent(BlockExplodeEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleBlockDamage((BlockExplodeEvent) event), Extension.getInstance(), true); + Bukkit.getPluginManager().registerEvent(BlockDamageEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleBlockDamage((BlockDamageEvent) event), Extension.getInstance(), true); + Bukkit.getPluginManager().registerEvent(BlockBurnEvent.class, this, EventPriority.HIGHEST, (listener, event) -> handleBlockDamage((BlockBurnEvent) event), Extension.getInstance(), true); + } + + // -----> Block placements + /** + * Handles block placements. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handleBlockPlace(@NotNull BlockPlaceEvent event) { + PSPlayer player = PSPlayerFactory.get(event.getPlayer()); + + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handleWorldBlockPlace(player, event)); + } + + + // -----> Block updates + /** + * Handles block cooks. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handleBlockUpdate(@NotNull BlockCookEvent event) { + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handleWorldBlockUpdate(event)); + } + + /** + * Handles block dispenses. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handleBlockUpdate(@NotNull BlockDispenseEvent event) { + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handleWorldBlockUpdate(event)); + } + + /** + * Handles block explosions. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handleBlockUpdate(@NotNull BlockRedstoneEvent event) { + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handleWorldBlockUpdate(event)); + } + + /** + * Handles block explosions. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handleBlockUpdate(@NotNull BlockPistonEvent event) { + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handleWorldBlockUpdate(event)); + } + + /** + * Handles block experience. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handleBlockUpdate(@NotNull BlockExpEvent event) { + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handleWorldBlockUpdate(event)); + } + + + // -----> Block damage + /** + * Handles block break progress. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handleBlockDamage(@NotNull BlockBreakProgressUpdateEvent event) { + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handleWorldBlockDamage(event)); + } + + /** + * Handles block breaks. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handleBlockDamage(@NotNull BlockBreakEvent event) { + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handleWorldBlockDamage(event)); + } + + /** + * Handles block explosions. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handleBlockDamage(@NotNull BlockExplodeEvent event) { + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handleWorldBlockDamage(event)); + } + + /** + * Handles block damage. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handleBlockDamage(@NotNull BlockDamageEvent event) { + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handleWorldBlockDamage(event)); + } + + /** + * Handles block burns. + * + * @param event event information + * @since v1-release0 + */ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void handleBlockDamage(@NotNull BlockBurnEvent event) { + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.handleWorldBlockDamage(event)); + } +} diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/misc/Miscellaneous.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/misc/Miscellaneous.java new file mode 100644 index 0000000..adb8478 --- /dev/null +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/misc/Miscellaneous.java @@ -0,0 +1,54 @@ +/* + * 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 . + */ + +package de.jeremystartm.pickshadow.extension.misc; + +import org.jetbrains.annotations.NotNull; + +import java.time.LocalTime; + +/** + * Translation real time to Minecraft time. + * + * @since v1-release0 + */ +public final class Miscellaneous { + /** + * Translation real time to Minecraft time. + * + * @param localTime {@link LocalTime} instance + * @return Minecraft time + * @since v1-release0 + */ + public static long translateTime(@NotNull LocalTime localTime) { + long time = -6000L; + + // Translate hours, minutes & seconds + time += localTime.getHour() * 1000; + time += localTime.getMinute() * 2 * 10; + time += (localTime.getSecond() - localTime.getSecond() % 10) / 10 * 2; + + // Limit numbers + // Prevent negative numbers + if (time < 0) + time = 24000 + time; + + return time; + } +} diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/misc/Scheduler.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/misc/Scheduler.java index 7a05c18..31f3031 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/misc/Scheduler.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/misc/Scheduler.java @@ -23,6 +23,7 @@ import de.jeremystartm.pickshadow.extension.BuildOptions; import de.jeremystartm.pickshadow.extension.Extension; import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; +import de.jeremystartm.pickshadow.extension.implementable.ServerMode; import de.staropensource.engine.base.logging.Logger; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import net.luckperms.api.util.Tristate; @@ -68,6 +69,8 @@ public final class Scheduler { */ public static void world(@NotNull World world) { try { + for (ServerMode mode : ServerMode.getInitializedModes(false)) + mode.updateWorld(world); killBats(world); } catch (Exception exception) { Logger.crash("World scheduler failed for '" + world.getName() + "'", exception); @@ -88,6 +91,9 @@ public final class Scheduler { // Apply damage DamageDetection.apply(player); + // Call modes + ServerMode.getInitializedModes(false).forEach(mode -> mode.updatePlayer(player)); + // Reschedule player.schedule(() -> player(player), 1L); } catch (Exception exception) { diff --git a/extension/src/main/resources/plugin.yml b/extension/src/main/resources/plugin.yml index 51dd97f..1029db5 100644 --- a/extension/src/main/resources/plugin.yml +++ b/extension/src/main/resources/plugin.yml @@ -5,11 +5,13 @@ description: "Manages PickShadow's subservers" author: "PickShadow Server Extension Authors" website: "https://git.staropensource.de/JeremyStarTM/PickShadow" api-version: "${minecraftApi}" -load: POSTWORLD +load: "POSTWORLD" prefix: "PSSE" depend: - "sosenginemc" - "LuckPerms" +loadbefore: + - "WorldGuard" commands: # General @@ -32,7 +34,7 @@ commands: # -> ExtensionCommand psse: description: "Interface for players and administrators to PSSE and the PickShadow network." - usage: "/psse " + usage: "/psse " aliases: - pickshadow - server @@ -126,6 +128,14 @@ commands: - rl + # Multi-mode + # -> SpawnCommand + spawn: + description: "Teleports the specified player to spawn." + usage: "/spawn" + aliases: [] + + # Survival # -> HomeCommand home: @@ -242,6 +252,13 @@ permissions: default: false + # Multi-mode + # -> SpawnCommand + pickshadow.command.spawn: + description: "Provides access to the '/spawn' command." + default: false + + # -> Survival # --> HomeCommand pickshadow.command.home: diff --git a/extension/src/main/resources/translations/de.json b/extension/src/main/resources/translations/de.json index fe5d9d8..d5829da 100644 --- a/extension/src/main/resources/translations/de.json +++ b/extension/src/main/resources/translations/de.json @@ -17,10 +17,15 @@ "CONNECTION_ERROR_TABLISTHANDLER": "Der TabListHandler schlug unerwartet fehl", "CONNECTION_ERROR_SCHEDULER": "Der Player Scheduler schlug unerwartet fehl", - "EXTENSIONCMD_GREETER": "Dieser Subserver läuft <#d60532>PSSE \"%codename%\" @ %version% (%commit%, dirty %dirty%)\nFühre ein paar Subbefehle aus um mehr Informationen einzusehen.", - "EXTENSIONCMD_KILLJVM": "Bye bye!", + "EXTENSIONCMD": "Dieser Subserver läuft <#d60532>PSSE \"%codename%\" @ %version% (%commit%, dirty %dirty%)\nFühre ein paar Subbefehle aus um mehr Informationen einzusehen.", "EXTENSIONCMD_LICENSE": "PSSE ist lizensiert unter der %license%.", "EXTENSIONCMD_SOURCE": "Du kannst PickShadow's serverseitigen Code auf sos!git finden.", + "EXTENSIONCMD_MODES": "Dieser Subserver hat die folgenden Modi aktiviert: %modes%", + "EXTENSIONCMD_MODES_ENABLE": "Alle Modi wurden aktiviert.", + "EXTENSIONCMD_MODES_DISABLE": "Alle Modi wurden deaktiviert.", + "EXTENSIONCMD_KILLJVM": "Bye bye!", + "EXTENSIONCMD_INTERNAL_DEVELOPMENTMODE": "%mode% ist in Entwicklung und wird bald verfügbar sein, tut uns leid.", + "EXTENSIONCMD_INTERNAL_SENDTOSERVER": "Sende dich nach %server%...", "LEGACYEXTENSIONCMD": "Was ist PSSP...?\nDas PickShadow Server Plugin (PSSP) wurde in PickShadow Server Extension (PSSE) umbenannt.\nBitte verwende diesen Namen stattdessen, vielen Dank.", @@ -82,5 +87,8 @@ "SPEED_FLY": "Fluggeschwindigkeit", "SPEED_WALK": "Laufgeschwindigkeit", + "SPAWN": "Du wurdest zum Spawn teleportiert.", + "SPAWN_REMOTE": "%player% wurde zum Spawn teleportiert.", + "CHATCOMMAND_ERROR_NAMESPACE": "Namespaces zu verwenden ist nicht erlaubt, da es verwendet werden kann um Sicherheitsmaßnahmen zu umgehen." } diff --git a/extension/src/main/resources/translations/en.json b/extension/src/main/resources/translations/en.json index b74030b..e9a1d98 100644 --- a/extension/src/main/resources/translations/en.json +++ b/extension/src/main/resources/translations/en.json @@ -29,10 +29,15 @@ "CONNECTION_ERROR_TABLISTHANDLER": "The TabListHandler failed unexpectedly", "CONNECTION_ERROR_SCHEDULER": "The player scheduler failed unexpectedly", - "EXTENSIONCMD_GREETER": "This subserver is running <#d60532>PSSE \"%codename%\" @ %version% (%commit%, dirty %dirty%)\nTo view additional information, invoke some subcommands.", - "EXTENSIONCMD_KILLJVM": "Bye bye!", + "EXTENSIONCMD": "This subserver is running <#d60532>PSSE \"%codename%\" @ %version% (%commit%, dirty %dirty%)\nTo view additional information, invoke some subcommands.", "EXTENSIONCMD_LICENSE": "PSSE is licensed under the %license%.", "EXTENSIONCMD_SOURCE": "You can find the source code of PickShadow's server-side code on sos!git.", + "EXTENSIONCMD_MODES": "This subserver has the following modes enabled: %modes%", + "EXTENSIONCMD_MODES_ENABLE": "All modes have been enabled.", + "EXTENSIONCMD_MODES_DISABLE": "All modes have been disabled.", + "EXTENSIONCMD_KILLJVM": "Bye bye!", + "EXTENSIONCMD_INTERNAL_DEVELOPMENTMODE": "%mode% is in development and will be available soon, sorry.", + "EXTENSIONCMD_INTERNAL_SENDTOSERVER": "Sending you to %server%...", "LEGACYEXTENSIONCMD": "What's PSSP...?\nThe PickShadow Server Plugin (PSSP) has been renamed into PickShadow Server Extension (PSSE).\nPlease use the new name from now on. Thank you.", @@ -101,5 +106,8 @@ "SPEED_FLY": "fly speed", "SPEED_WALK": "walk speed", + "SPAWN": "You were teleported to spawn.", + "SPAWN_REMOTE": "%player% has been teleported to spawn.", + "CHATCOMMAND_ERROR_NAMESPACE": "Using namespaces is not allowed, as it may be used to circumvent security measures." }