Add server modes, more event listeners and more

This commit is contained in:
JeremyStar™ 2024-11-21 15:14:57 +01:00
parent 44dab9e11b
commit 44fd5ed427
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
43 changed files with 1699 additions and 68 deletions

View file

@ -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"

1 TYPE CATEGORY NULLVALUE RETURN TYPE METHODNAME METHODARGUMENTS
27 INSTANCE Health @NotNull PSPlayer damage double healthPoints
28 INSTANCE Health @NotNull PSPlayer damage double healthPoints, @NotNull Entity entity
29 INSTANCE Health @NotNull PSPlayer damage double healthPoints, @NotNull DamageSource damageSource
30 INSTANCE Health @NotNull PSPlayer kill
31 INSTANCE Health @NotNull PSPlayer kill @NotNull Entity entity
32 INSTANCE Health @NotNull PSPlayer kill @NotNull DamageSource damageSource
33 INSTANCE Hunger int getHunger
34 INSTANCE Hunger float getSaturation
35 INSTANCE Hunger @NotNull PSPlayer setHunger int hungerPoints

View file

@ -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
/**

View file

@ -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");
}

View file

@ -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: <x>,<y>,<z>,<yaw>,<pitch>[,<world>])");
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 ? "<none>" : 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;
};
}

View file

@ -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.
* <p>
* 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

View file

@ -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
/**

View file

@ -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,
}

View file

@ -67,7 +67,7 @@ public final class TemplateCommand extends CommandForced {
new String[]{ "alias 1", "alias 2" },
"An example command",
"/cmd [--verbose] <arg1|arg2|arg3>",
"mode",
new String[] { "mode" },
null,
ExecutionTarget.ALL
), "cmd");

View file

@ -65,7 +65,7 @@ public final class AnnounceCommand extends Command {
new String[]{ "announce", "announcement", "broadcast", "bc" },
"",
"",
"general",
new String[]{ "general" },
null,
ExecutionTarget.ALL
), "announce");

View file

@ -72,7 +72,7 @@ public final class ClearChatCommand extends Command {
new String[]{ "clearchat", "chatclear", "cc" },
"",
"",
"general",
new String[]{ "general" },
null,
ExecutionTarget.ALL
), "clearchat");

View file

@ -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])));
}
if (arguments[0].equals("killjvm"))
Runtime.getRuntime().halt(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])));
}
}
}

View file

@ -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");

View file

@ -59,7 +59,7 @@ public final class LegacyExtensionCommand extends Command {
new String[]{ "pssp" },
"",
"/pssp",
"general",
new String[]{ "general" },
null,
ExecutionTarget.PLAYERS_ONLY
), "pssp");

View file

@ -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");

View file

@ -83,7 +83,7 @@ public final class SpeedCommand extends Command {
new String[]{ "speed" },
"",
"",
"general",
new String[]{ "general" },
null,
ExecutionTarget.CONSOLE_PARTIAL
), "speed");

View file

@ -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" -> {

View file

@ -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'

View file

@ -60,7 +60,7 @@ public final class HelpCommand extends Command {
new String[]{ "help", "?" },
"",
"",
"general",
new String[]{ "general" },
null,
ExecutionTarget.ALL
), "help");

View file

@ -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");

View file

@ -65,7 +65,7 @@ public final class PluginsCommand extends Command {
new String[]{ "plugins", "pl" },
"",
"",
"general",
new String[]{ "general" },
null,
ExecutionTarget.ALL
));

View file

@ -60,7 +60,7 @@ public final class ReloadCommand extends Command {
new String[]{ "reload", "rl" },
"",
"",
"general",
new String[]{ "general" },
null,
ExecutionTarget.ALL
));

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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())
);
}
}

View file

@ -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");

View file

@ -66,7 +66,7 @@ public final class FeedCommand extends Command {
new String[]{ "feed" },
"",
"",
"survivalcheat",
new String[]{ "survivalcheat" },
null,
ExecutionTarget.CONSOLE_PARTIAL
), "feed");

View file

@ -73,7 +73,7 @@ public final class HealCommand extends Command {
new String[]{ "heal" },
"",
"",
"survivalcheat",
new String[]{ "survivalcheat" },
null,
ExecutionTarget.CONSOLE_PARTIAL
), "heal");

View file

@ -63,7 +63,7 @@ public final class ToggleDownfallCommand extends Command {
new String[]{ "toggledownfall" },
"",
"",
"survivalcheat",
new String[]{ "survivalcheat" },
null,
ExecutionTarget.PLAYERS_ONLY
), "toggledownfall");

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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<? super Object>) 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.
* <p>
* 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.
* <p>
* Called every tick.
*
* @param world world to update
* @since v1-release0
*/
public void updateWorld(@NotNull World world) {}
/**
* Updates the specified player.
* <p>
* 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.
* <p>
* 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.
* <p>
* This method only works during the
* mode initialization process.
*
* @param <T> value type
* @param gameRule game rule to change
* @param value value to change the game rule to
* @since v1-release0
*/
public <T> @NotNull ServerMode setGameRule(@NotNull GameRule<T> 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;
}
}

View file

@ -0,0 +1,25 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Interfaces and abstract classes which can be used for implementing classes.
*
* @since v1-release0
*/
package de.jeremystartm.pickshadow.extension.implementable;

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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) {}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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);
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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) {}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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) {}
}

View file

@ -0,0 +1,25 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Classes handling different server modes.
*
* @since v1-release0
*/
package de.jeremystartm.pickshadow.extension.implementation.mode;

View file

@ -0,0 +1,25 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Implementations for various interfaces and abstract classes.
*
* @since v1-release0
*/
package de.jeremystartm.pickshadow.extension.implementation;

View file

@ -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.
*

View file

@ -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());

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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));
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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));
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View file

@ -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) {

View file

@ -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 <license|source|killjvm>"
usage: "/psse <license|source|modes|disableModes|killjvm>"
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:

View file

@ -17,10 +17,15 @@
"CONNECTION_ERROR_TABLISTHANDLER": "<error>Der TabListHandler schlug unerwartet fehl</error>",
"CONNECTION_ERROR_SCHEDULER": "<error>Der Player Scheduler schlug unerwartet fehl</error>",
"EXTENSIONCMD_GREETER": "<generic>Dieser Subserver läuft <#d60532><bold>PSSE</bold> \"<italic>%codename%</italic>\" <italic>@ %version% (%commit%, dirty %dirty%)</italic></generic>\n<generic>Führe ein paar Subbefehle aus um mehr Informationen einzusehen.</generic>",
"EXTENSIONCMD_KILLJVM": "<generic>Bye bye!</generic>",
"EXTENSIONCMD": "<generic>Dieser Subserver läuft <#d60532><bold>PSSE</bold> \"<italic>%codename%</italic>\" <italic>@ %version% (%commit%, dirty %dirty%)</italic></generic>\n<generic>Führe ein paar Subbefehle aus um mehr Informationen einzusehen.</generic>",
"EXTENSIONCMD_LICENSE": "<generic>PSSE ist lizensiert unter der <click:open_url:%license_url%><link>%license%</link></click>.</generic>",
"EXTENSIONCMD_SOURCE": "<generic>Du kannst PickShadow's serverseitigen Code auf <click:open_url:%source%><link>sos!git</link></click> finden.</generic>",
"EXTENSIONCMD_MODES": "<generic>Dieser Subserver hat die folgenden Modi aktiviert: <mention>%modes%</mention></generic>",
"EXTENSIONCMD_MODES_ENABLE": "<generic>Alle Modi wurden <mention>aktiviert</mention>.</generic>",
"EXTENSIONCMD_MODES_DISABLE": "<generic>Alle Modi wurden <mention>deaktiviert</mention>.</generic>",
"EXTENSIONCMD_KILLJVM": "<generic>Bye bye!</generic>",
"EXTENSIONCMD_INTERNAL_DEVELOPMENTMODE": "<error><mention>%mode%</mention> ist in Entwicklung und wird bald verfügbar sein, tut uns leid.</error>",
"EXTENSIONCMD_INTERNAL_SENDTOSERVER": "<generic>Sende dich nach <mention>%server%</mention>...</generic>",
"LEGACYEXTENSIONCMD": "<error>Was ist <mention>PSSP</mention>...?</error>\n<error>Das PickShadow Server Plugin (PSSP) wurde in PickShadow Server <italic>Extension</italic> (PSSE) umbenannt.</error>\n<error>Bitte verwende diesen Namen stattdessen, vielen Dank.</error>",
@ -82,5 +87,8 @@
"SPEED_FLY": "Fluggeschwindigkeit",
"SPEED_WALK": "Laufgeschwindigkeit",
"SPAWN": "<generic>Du wurdest zum Spawn teleportiert.",
"SPAWN_REMOTE": "<generic><mention>%player%</mention> wurde zum Spawn teleportiert.",
"CHATCOMMAND_ERROR_NAMESPACE": "<error>Namespaces zu verwenden ist nicht erlaubt, da es verwendet werden kann um Sicherheitsmaßnahmen zu umgehen.</error>"
}

View file

@ -29,10 +29,15 @@
"CONNECTION_ERROR_TABLISTHANDLER": "<error>The TabListHandler failed unexpectedly</error>",
"CONNECTION_ERROR_SCHEDULER": "<error>The player scheduler failed unexpectedly</error>",
"EXTENSIONCMD_GREETER": "<generic>This subserver is running <#d60532><bold>PSSE</bold> \"<italic>%codename%</italic>\" <italic>@ %version% (%commit%, dirty %dirty%)</italic></generic>\n<generic>To view additional information, invoke some subcommands.</generic>",
"EXTENSIONCMD_KILLJVM": "<generic>Bye bye!</generic>",
"EXTENSIONCMD": "<generic>This subserver is running <#d60532><bold>PSSE</bold> \"<italic>%codename%</italic>\" <italic>@ %version% (%commit%, dirty %dirty%)</italic></generic>\n<generic>To view additional information, invoke some subcommands.</generic>",
"EXTENSIONCMD_LICENSE": "<generic>PSSE is licensed under the <click:open_url:%license_url%><link>%license%</link></click>.</generic>",
"EXTENSIONCMD_SOURCE": "<generic>You can find the source code of PickShadow's server-side code on <click:open_url:%source%><link>sos!git</link></click>.</generic>",
"EXTENSIONCMD_MODES": "<generic>This subserver has the following modes enabled: <mention>%modes%</mention></generic>",
"EXTENSIONCMD_MODES_ENABLE": "<generic>All modes have been <mention>enabled</mention>.</generic>",
"EXTENSIONCMD_MODES_DISABLE": "<generic>All modes have been <mention>disabled</mention>.</generic>",
"EXTENSIONCMD_KILLJVM": "<generic>Bye bye!</generic>",
"EXTENSIONCMD_INTERNAL_DEVELOPMENTMODE": "<error><mention>%mode%</mention> is in development and will be available soon, sorry.</error>",
"EXTENSIONCMD_INTERNAL_SENDTOSERVER": "<generic>Sending you to <mention>%server%</mention>...</generic>",
"LEGACYEXTENSIONCMD": "<error>What's <mention>PSSP</mention>...?</error>\n<error>The PickShadow Server <italic>Plugin</italic> (PSSP) has been renamed into PickShadow Server <italic>Extension</italic> (PSSE).</error>\n<error>Please use the new name from now on. Thank you.</error>",
@ -101,5 +106,8 @@
"SPEED_FLY": "fly speed",
"SPEED_WALK": "walk speed",
"SPAWN": "<generic>You were teleported to spawn.",
"SPAWN_REMOTE": "<generic><mention>%player%</mention> has been teleported to spawn.",
"CHATCOMMAND_ERROR_NAMESPACE": "<error>Using namespaces is not allowed, as it may be used to circumvent security measures.</error>"
}