Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<name>SimpleBack</name>

<properties>
<java.version>17</java.version>
<java.version>21</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

Expand Down Expand Up @@ -65,7 +65,7 @@
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.20.4-R0.1-SNAPSHOT</version>
<version>1.21.5-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
Expand Down
24 changes: 14 additions & 10 deletions src/main/java/simplexity/simpleback/SimpleBack.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package simplexity.simpleback;

import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Location;
import org.bukkit.plugin.java.JavaPlugin;
import simplexity.simpleback.commands.Back;
import simplexity.simpleback.commands.BackReload;
import simplexity.simpleback.config.ConfigHandler;
import simplexity.simpleback.listeners.DeathListener;
import simplexity.simpleback.listeners.JoinListener;
import simplexity.simpleback.listeners.LeaveListener;
import simplexity.simpleback.listeners.MovementListener;
import simplexity.simpleback.listeners.TeleportListener;
import simplexity.simpleback.handlers.BackPermission;
import simplexity.simpleback.listeners.*;

import java.util.HashMap;
import java.util.UUID;

@SuppressWarnings("UnstableApiUsage")
public final class SimpleBack extends JavaPlugin {
private final HashMap<UUID, Location> backLocations = new HashMap<>();
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
Expand All @@ -27,17 +26,22 @@ public void onEnable() {
getConfig().options().copyDefaults(true);
saveConfig();
ConfigHandler.getInstance().loadConfigValues();
registerPermissions();
this.getServer().getPluginManager().registerEvents(new TeleportListener(), this);
this.getServer().getPluginManager().registerEvents(new MovementListener(), this);
this.getServer().getPluginManager().registerEvents(new JoinListener(), this);
this.getServer().getPluginManager().registerEvents(new LeaveListener(), this);
this.getServer().getPluginManager().registerEvents(new DeathListener(), this);
//noinspection DataFlowIssue
this.getCommand("back").setExecutor(new Back());
//noinspection DataFlowIssue
this.getCommand("backreload").setExecutor(new BackReload());
// Plugin startup logic
this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> {
commands.registrar().register(Back.createCommand().build());
commands.registrar().register(BackReload.createCommand().build());
});
}

private void registerPermissions(){
for (BackPermission permission : BackPermission.values()) {
this.getServer().getPluginManager().addPermission(permission.getPermission());
}
}

public HashMap<UUID, Location> getBackLocations() {
Expand Down
91 changes: 63 additions & 28 deletions src/main/java/simplexity/simpleback/commands/Back.java
Original file line number Diff line number Diff line change
@@ -1,42 +1,77 @@
package simplexity.simpleback.commands;

import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.command.brigadier.argument.ArgumentTypes;
import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import simplexity.simpleback.config.ConfigHandler;
import simplexity.simpleback.config.Message;
import simplexity.simpleback.SimpleBack;
import simplexity.simpleback.config.ConfigHandler;
import simplexity.simpleback.handlers.CooldownHandler;
import simplexity.simpleback.handlers.MessageHandler;
import simplexity.simpleback.handlers.BackPermission;
import simplexity.simpleback.handlers.TeleportHandler;

public class Back implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) {
if (!(sender instanceof Player player)) {
sender.sendRichMessage(Message.ERROR_MUST_BE_PLAYER.getMessage());
return true;
}
if (!SimpleBack.getInstance().getBackLocations().containsKey(player.getUniqueId())) {
player.sendRichMessage(Message.ERROR_NO_BACK_LOCATIONS.getMessage());
return true;
}
if (!CooldownHandler.cooldownExpired(player)) {
player.sendMessage(MessageHandler.getParsedTimeMessage(Message.ERROR_COOLDOWN,
CooldownHandler.getLeftoverCooldownTime(player.getUniqueId())));
return false;
}
if (TeleportHandler.blacklistedWorld(player)) {
player.sendRichMessage(Message.ERROR_BLACKLISTED_WORLD.getMessage());
return false;
import java.util.List;

@SuppressWarnings({"UnstableApiUsage", "SameReturnValue"})
public class Back {

public static LiteralArgumentBuilder<CommandSourceStack> createCommand() {
return Commands.literal("back")
.requires(Back::canExecute)
.executes(Back::execute)
.then(Commands.argument("player", ArgumentTypes.player())
.requires(Back::canExecuteWithArg)
.executes(Back::executeWithArg));
}


private static int execute(CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
if (!(ctx.getSource().getSender() instanceof Player player)) throw Exceptions.MUST_PROVIDE_PLAYER.create();
if (!SimpleBack.getInstance().getBackLocations().containsKey(player.getUniqueId()))
throw Exceptions.NO_BACK_LOCATIONS.create();
if (!CooldownHandler.cooldownExpired(player))
throw Exceptions.COOLDOWN_NOT_FINISHED.create(CooldownHandler.getLeftoverCooldownTime(player.getUniqueId()));
if (TeleportHandler.blacklistedWorld(player)) throw Exceptions.BLACKLISTED_WORLD.create();
if (ConfigHandler.getInstance().isTeleportDelay()) {
TeleportHandler.delayTeleport(player);
return Command.SINGLE_SUCCESS;
}
TeleportHandler.teleport(player);
return Command.SINGLE_SUCCESS;
}

private static int executeWithArg(CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
PlayerSelectorArgumentResolver argResolver = ctx.getArgument("player", PlayerSelectorArgumentResolver.class);
List<Player> playerList = argResolver.resolve(ctx.getSource());
if (playerList.isEmpty()) throw Exceptions.PLAYER_NOT_FOUND.create();
Player player = playerList.getFirst();
if (!SimpleBack.getInstance().getBackLocations().containsKey(player.getUniqueId()))
throw Exceptions.NO_BACK_LOCATIONS.create();
if (!CooldownHandler.cooldownExpired(player))
throw Exceptions.COOLDOWN_NOT_FINISHED.create(CooldownHandler.getLeftoverCooldownTime(player.getUniqueId()));
if (TeleportHandler.blacklistedWorld(player)) throw Exceptions.BLACKLISTED_WORLD.create();
if (ConfigHandler.getInstance().isTeleportDelay()) {
TeleportHandler.delayTeleport(player);
return true;
return Command.SINGLE_SUCCESS;
}
TeleportHandler.teleport(player);
return true;
return Command.SINGLE_SUCCESS;
}

private static boolean canExecute(CommandSourceStack css) {
if (css.getSender() instanceof Player player) {
return player.hasPermission(BackPermission.BACK_USE.getPermission());
}
return css.getSender().hasPermission(BackPermission.FORCE_BACK.getPermission());
}

private static boolean canExecuteWithArg(CommandSourceStack css) {
if (css.getSender() instanceof Player) return false;
return css.getSender().hasPermission(BackPermission.FORCE_BACK.getPermission());
}
}
31 changes: 18 additions & 13 deletions src/main/java/simplexity/simpleback/commands/BackReload.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
package simplexity.simpleback.commands;

import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import simplexity.simpleback.config.ConfigHandler;
import simplexity.simpleback.config.Message;
import simplexity.simpleback.handlers.CacheHandler;
import simplexity.simpleback.config.LocaleMessage;
import simplexity.simpleback.handlers.BackPermission;

public class BackReload implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s, @NotNull String[] args) {
CacheHandler.clearCache();
ConfigHandler.getInstance().loadConfigValues();
sender.sendRichMessage(Message.PLUGIN_RELOADED.getMessage());
return true;
@SuppressWarnings("UnstableApiUsage")
public class BackReload {

public static LiteralArgumentBuilder<CommandSourceStack> createCommand() {
return Commands.literal("backreload")
.requires(css -> css.getSender().hasPermission(BackPermission.BACK_RELOAD.getPermission()))
.executes(css -> {
ConfigHandler.getInstance().loadConfigValues();
css.getSource().getSender().sendRichMessage(LocaleMessage.PLUGIN_RELOADED.getMessage());
return Command.SINGLE_SUCCESS;
});
Comment on lines +16 to +21
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to create a separate method for readability and consistency with Back?

}

}
43 changes: 43 additions & 0 deletions src/main/java/simplexity/simpleback/commands/Exceptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package simplexity.simpleback.commands;

import com.mojang.brigadier.Message;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import io.papermc.paper.command.brigadier.MessageComponentSerializer;
import net.kyori.adventure.text.minimessage.MiniMessage;
import simplexity.simpleback.SimpleBack;
import simplexity.simpleback.config.LocaleMessage;
import simplexity.simpleback.handlers.MessageHandler;

@SuppressWarnings("UnstableApiUsage")
public class Exceptions {
private static final MiniMessage miniMessage = SimpleBack.getMiniMessage();

public static final SimpleCommandExceptionType NO_BACK_LOCATIONS = new SimpleCommandExceptionType(
parseMessage(LocaleMessage.ERROR_NO_BACK_LOCATIONS)
);

public static final SimpleCommandExceptionType BLACKLISTED_WORLD = new SimpleCommandExceptionType(
parseMessage(LocaleMessage.ERROR_BLACKLISTED_WORLD)
);

public static final SimpleCommandExceptionType PLAYER_NOT_FOUND = new SimpleCommandExceptionType(
parseMessage(LocaleMessage.ERROR_PLAYER_INVALID)
);

public static final SimpleCommandExceptionType MUST_PROVIDE_PLAYER = new SimpleCommandExceptionType(
parseMessage(LocaleMessage.ERROR_MUST_PROVIDE_PLAYER)
);

public static final DynamicCommandExceptionType COOLDOWN_NOT_FINISHED = new DynamicCommandExceptionType(time -> {
return MessageComponentSerializer.message().serialize(
MessageHandler.getParsedTimeMessage(LocaleMessage.ERROR_COOLDOWN, (long) time)
);
});
Comment on lines +32 to +36
Copy link
Member

@Peashooter101 Peashooter101 Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lambda function does not need to be bracketed with a return.

A -> B already implies A -> { return B; }

Suggested change
public static final DynamicCommandExceptionType COOLDOWN_NOT_FINISHED = new DynamicCommandExceptionType(time -> {
return MessageComponentSerializer.message().serialize(
MessageHandler.getParsedTimeMessage(LocaleMessage.ERROR_COOLDOWN, (long) time)
);
});
public static final DynamicCommandExceptionType COOLDOWN_NOT_FINISHED = new DynamicCommandExceptionType(
time -> MessageComponentSerializer.message().serialize(
MessageHandler.getParsedTimeMessage(LocaleMessage.ERROR_COOLDOWN, (long) time)
)
);

Since this can be pretty hard to read, you can use the brackets with return, but you may want to break your single statement into multiple lines.


private static Message parseMessage(LocaleMessage message){
return MessageComponentSerializer.message().serialize(
miniMessage.deserialize(message.getMessage())
);
}
}
14 changes: 7 additions & 7 deletions src/main/java/simplexity/simpleback/config/LocaleHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,16 @@ public void reloadLocale() {


private void populateLocale() {
Set<Message> missing = new HashSet<>(Arrays.asList(Message.values()));
for (Message message : Message.values()) {
if (locale.contains(message.getPath())) {
message.setMessage(locale.getString(message.getPath()));
missing.remove(message);
Set<LocaleMessage> missing = new HashSet<>(Arrays.asList(LocaleMessage.values()));
for (LocaleMessage localeMessage : LocaleMessage.values()) {
if (locale.contains(localeMessage.getPath())) {
localeMessage.setMessage(locale.getString(localeMessage.getPath()));
missing.remove(localeMessage);
}
}

for (Message message : missing) {
locale.set(message.getPath(), message.getMessage());
for (LocaleMessage localeMessage : missing) {
locale.set(localeMessage.getPath(), localeMessage.getMessage());
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package simplexity.simpleback.config;

public enum Message {
public enum LocaleMessage {
TELEPORT_PLEASE_WAIT("message.teleport-delay", "<green>Teleporting! Please wait <value> seconds!</green>"),
TELEPORT_SUCCESSFUL("message.teleport-successful", "<green>Successfully teleported to <x-loc>, <y-loc>, <z-loc> in <world>!"),
TELEPORT_CANCELLED("message.teleport-cancelled", "<red>Teleport Cancelled</red>"),
Expand All @@ -12,14 +12,16 @@ public enum Message {
INSERT_MINUTE("insert.minute", "<yellow><minute>m </yellow>"),
INSERT_SECOND("insert.second", "<yellow><second>s</yellow>"),
ERROR_MUST_BE_PLAYER("error.must-be-player", "<red>Sorry, you must be a player to run this command!</red>"),
ERROR_MUST_PROVIDE_PLAYER("error.must-provide-player", "<red>You must provide a valid player for this command!</red>"),
ERROR_PLAYER_INVALID("error.player-invalid", "<red>Player not found</red>"),
ERROR_NO_BACK_LOCATIONS("error.no-back-locations", "<gray>No back locations found!</gray>"),
ERROR_COOLDOWN("error.command-cooldown", "<gray>Sorry, that command is on cooldown for: [<hour><minute><second>]!</gray>"),
ERROR_BLACKLISTED_WORLD("error.blacklisted-world", "<red>Sorry, the world you are trying to return to is blacklisted!</red>"),
PLUGIN_RELOADED("plugin.reloaded", "<gold>SimpleBack plugin reloaded</gold>");
private final String path;
private String message;

Message(String path, String message) {
LocaleMessage(String path, String message) {
this.path = path;
this.message = message;
}
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/simplexity/simpleback/handlers/BackPermission.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package simplexity.simpleback.handlers;

import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;

public enum BackPermission {
// Declaration order so I don't keep having to look and forget
// Permission(@NotNull String name,
// @Nullable String description,
// @Nullable PermissionDefault defaultValue,
// @Nullable Map<String, Boolean> children)

BACK_USE(new Permission("back.use", "Allows the player to use the back command", PermissionDefault.TRUE)),
FORCE_BACK(new Permission("back.force", "Runs /back for another player", PermissionDefault.OP)),
BACK_RELOAD(new Permission("back.reload", "Allows the player to reload the SimpleBack config", PermissionDefault.OP)),
DELAY_BYPASS(new Permission("back.bypass.delay", "Bypass the teleport delay completely", PermissionDefault.OP)),
MOVEMENT_BYPASS(new Permission("back.bypass.movement", "Bypass the 'no movement' requirement of the teleport delay", PermissionDefault.OP)),
WORLD_BYPASS(new Permission("back.bypass.worlds", "Bypass the worlds blacklist for /back", PermissionDefault.OP)),
COOLDOWN_BYPASS(new Permission("back.bypass.cooldown", "Bypass the cooldown on /back", PermissionDefault.OP));

private final Permission permission;

BackPermission(Permission permission) {
this.permission = permission;
}

public Permission getPermission() {
return permission;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
import java.util.HashMap;
import java.util.UUID;

@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public class CooldownHandler {
public static final HashMap<UUID, Long> cooldownTime = new HashMap<>();

static void addToCooldown(@NotNull Player player) {
if (!ConfigHandler.getInstance().isTeleportCooldown()) return;
if (player.hasPermission(Permissions.COOLDOWN_BYPASS)) return;
if (player.hasPermission(BackPermission.COOLDOWN_BYPASS.getPermission())) return;
UUID uuid = player.getUniqueId();
Long cooldownTimeMilli = System.currentTimeMillis() + (ConfigHandler.getInstance().getCooldownInSeconds() * 1000L);
cooldownTime.put(uuid, cooldownTimeMilli);
Expand All @@ -21,7 +22,7 @@ static void addToCooldown(@NotNull Player player) {
public static boolean cooldownExpired(@NotNull Player player) {
UUID uuid = player.getUniqueId();
if (!cooldownTime.containsKey(uuid)) return true;
if (player.hasPermission(Permissions.COOLDOWN_BYPASS)) return true;
if (player.hasPermission(BackPermission.COOLDOWN_BYPASS.getPermission())) return true;
long leftoverTime = getLeftoverCooldownTime(uuid);
return leftoverTime <= 0;
}
Expand Down
Loading