Compare commits

..

3 Commits

Author SHA1 Message Date
akastijn 85e5effc15 Update VillagerWorkstationEvent to remove outdated api use 2026-05-14 19:38:50 +02:00
akastijn 8ad6fe2608 Merge branch 'plot_rtp'
# Conflicts:
#	src/main/java/com/alttd/playerutils/PlayerUtils.java
#	src/main/java/com/alttd/playerutils/config/Config.java
#	src/main/java/com/alttd/playerutils/config/Messages.java
2026-05-14 19:31:47 +02:00
akastijn eb7bd6cc95 Added random plot command by Jakob Stranz 2026-05-12 20:06:47 +02:00
7 changed files with 241 additions and 68 deletions

View File

@ -47,4 +47,8 @@ dependencies {
compileOnly("org.projectlombok:lombok:1.18.38") compileOnly("org.projectlombok:lombok:1.18.38")
annotationProcessor("org.projectlombok:lombok:1.18.38") annotationProcessor("org.projectlombok:lombok:1.18.38")
implementation(platform("com.intellectualsites.bom:bom-newest:1.56"))
compileOnly("com.intellectualsites.plotsquared:plotsquared-core")
compileOnly("com.intellectualsites.plotsquared:plotsquared-bukkit") { isTransitive = false }
} }

View File

@ -14,8 +14,9 @@ dependencyResolutionManagement {
password = nexusPass password = nexusPass
} }
} }
maven("https://repo.destro.xyz/snapshots")
maven("https://jitpack.io") maven("https://jitpack.io")
// PlotSquared
maven("https://repo.papermc.io/repository/maven-public/")
} }
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
} }

View File

@ -2,7 +2,7 @@ package com.alttd.playerutils;
import com.alttd.playerutils.commands.PlayerUtilsCommand; import com.alttd.playerutils.commands.PlayerUtilsCommand;
import com.alttd.playerutils.commands.playerutils_subcommands.GhastSpeed; import com.alttd.playerutils.commands.playerutils_subcommands.GhastSpeed;
import com.alttd.playerutils.commands.playerutils_subcommands.RandomPlotPort; import com.alttd.playerutils.commands.playerutils_subcommands.RandomPlot;
import com.alttd.playerutils.commands.playerutils_subcommands.RotateBlock; import com.alttd.playerutils.commands.playerutils_subcommands.RotateBlock;
import com.alttd.playerutils.config.Config; import com.alttd.playerutils.config.Config;
import com.alttd.playerutils.config.KeyStorage; import com.alttd.playerutils.config.KeyStorage;
@ -22,12 +22,22 @@ public final class PlayerUtils extends JavaPlugin {
@Override @Override
public void onEnable() { public void onEnable() {
registerCommands();
reloadConfigs(); reloadConfigs();
registerCommands();
registerRandomPlot();
registerEvents(); registerEvents();
registerSchedulers(); registerSchedulers();
} }
private void registerRandomPlot() {
if (!getServer().getPluginManager().isPluginEnabled("PlotSquared")) {
log.warn("PlotSquared not found — random plot command will not be registered.");
return;
}
playerUtilsCommand.addSubCommand(new RandomPlot(this));
log.info("PlotSquared found - registered random plot command.");
}
@Override @Override
public void onDisable() { public void onDisable() {
KeyStorage.STORAGE.save(); KeyStorage.STORAGE.save();
@ -35,11 +45,6 @@ public final class PlayerUtils extends JavaPlugin {
private void registerCommands() { private void registerCommands() {
playerUtilsCommand = new PlayerUtilsCommand(this); playerUtilsCommand = new PlayerUtilsCommand(this);
if (getServer().getPluginManager().isPluginEnabled("PlotSquared")) {
playerUtilsCommand.addSubCommand(new RandomPlotPort(this));
} else {
log.warn("PlotSquared not found — rpp subcommand will not be registered.");
}
} }
private void registerEvents() { private void registerEvents() {

View File

@ -0,0 +1,181 @@
package com.alttd.playerutils.commands.playerutils_subcommands;
import com.alttd.playerutils.PlayerUtils;
import com.alttd.playerutils.commands.SubCommand;
import com.alttd.playerutils.config.Config;
import com.alttd.playerutils.config.Messages;
import com.plotsquared.bukkit.player.BukkitPlayer;
import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.events.TeleportCause;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.title.Title;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.Nullable;
import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
@Slf4j
@RequiredArgsConstructor
public class RandomPlot extends SubCommand {
private static final String PERMISSION = "playerutils.randomplot";
private final PlayerUtils plugin;
private final MiniMessage miniMessage = MiniMessage.miniMessage();
@Override
public boolean onCommand(CommandSender commandSender, String[] args) {
if (!(commandSender instanceof Player player)) {
commandSender.sendRichMessage(Messages.GENERIC.PLAYER_ONLY);
return true;
}
String worldName = player.getWorld().getName();
if (!Config.RANDOM_PLOT.ALLOWED_WORLDS.contains(worldName)) {
player.sendRichMessage(Messages.RANDOM_PLOT.WORLD_NOT_ALLOWED);
return true;
}
if (!player.hasPermission(PERMISSION)) {
player.sendRichMessage(Messages.GENERIC.NO_PERMISSION, Placeholder.parsed("permission", PERMISSION));
return true;
}
if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) {
player.sendRichMessage(Messages.RANDOM_PLOT.PLOT_SQUARED_NOT_ENABLED);
return true;
}
List<Plot> plots = collectPlots(worldName);
if (plots.isEmpty()) {
player.sendRichMessage(Messages.RANDOM_PLOT.NO_PLOTS_FOUND);
return true;
}
Plot target = plots.get(ThreadLocalRandom.current().nextInt(plots.size()));
player.sendRichMessage(Messages.RANDOM_PLOT.TELEPORT_START);
startCountdown(player, target);
return true;
}
// PlotSquared helpers
private List<Plot> collectPlots(String worldName) {
try {
return PlotSquared.get().getPlotAreaManager().getPlotAreasSet(worldName)
.stream()
.map(PlotArea::getPlots)
.flatMap(Collection::stream)
.toList();
} catch (Exception e) {
log.error("Failed to retrieve plots from PlotSquared for world '{}'", worldName, e);
}
return List.of();
}
private void teleportToPlot(Player player, Plot plot) {
try {
BukkitPlayer bPlayer = BukkitUtil.adapt(player);
plot.teleportPlayer(bPlayer, TeleportCause.PLUGIN, success -> {
if (Boolean.TRUE.equals(success)) {
player.sendRichMessage(Messages.RANDOM_PLOT.TELEPORT_SUCCESS,
Placeholder.parsed("plot_id", plot.getId().toSeparatedString(";")),
Placeholder.parsed("plot_owner", getOwner(plot)));
}
});
} catch (Exception e) {
log.error("Failed to teleport {} to plot {}", player.getName(), plot.getId(), e);
}
}
private String getOwner(Plot plot) {
String ownerName;
UUID owner = plot.getOwner();
if (owner == null) {
ownerName = "Unknown";
} else {
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(owner);
ownerName = offlinePlayer.getName();
if (ownerName == null) {
ownerName = "Unknown";
}
}
return ownerName;
}
// Countdown
private void startCountdown(Player player, Plot plot) {
final Location origin = player.getLocation().clone();
final int[] secondsLeft = {Config.RANDOM_PLOT.COUNTDOWN_SECONDS};
new BukkitRunnable() {
@Override
public void run() {
if (!player.isOnline()) {
cancel();
return;
}
// Movement check cancel if player moved more than 0.5 blocks on any axis
Location current = player.getLocation();
if (Math.abs(current.getX() - origin.getX()) > 0.5
|| Math.abs(current.getY() - origin.getY()) > 0.5
|| Math.abs(current.getZ() - origin.getZ()) > 0.5) {
cancel();
player.sendRichMessage(Messages.RANDOM_PLOT.TELEPORT_CANCELLED);
return;
}
if (secondsLeft[0] <= 0) {
cancel();
teleportToPlot(player, plot);
return;
}
// Show countdown title for current second
String rawTitle = Config.RANDOM_PLOT.COUNTDOWN_TITLES
.getOrDefault(secondsLeft[0], String.valueOf(secondsLeft[0]));
Component title = miniMessage.deserialize(rawTitle);
Component subtitle = miniMessage.deserialize(Config.RANDOM_PLOT.COUNTDOWN_SUBTITLE);
player.showTitle(Title.title(
title,
subtitle,
Title.Times.times(Duration.ZERO, Duration.ofMillis(1200), Duration.ofMillis(200))
));
secondsLeft[0]--;
}
}.runTaskTimer(plugin, 0L, 20L);
}
@Override
public String getName() {
return "randomplot";
}
@Override
public List<String> getTabComplete(CommandSender commandSender, String[] args) {
return List.of();
}
@Override
public String getHelpMessage() {
return Messages.HELP.RANDOM_PLOT;
}
}

View File

@ -8,7 +8,8 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@Slf4j public class Config extends AbstractConfig{ @Slf4j
public class Config extends AbstractConfig {
static Config config; static Config config;
@ -113,38 +114,17 @@ import java.util.Set;
private static final String prefix = "random-plot."; private static final String prefix = "random-plot.";
// Command // Command
public static String PORT_COMMAND = "rpp";
public static List<String> ALLOWED_WORLDS = List.of("plotworld"); public static List<String> ALLOWED_WORLDS = List.of("plotworld");
// Permissions // Permissions
public static boolean USE_LUCKPERMS = true;
public static String LUCKPERMS_GROUP = "default";
public static boolean USE_VAULT = false;
public static String VAULT_GROUP = "member";
public static String FALLBACK_PERM = "randomplot.use";
// Countdown
public static int COUNTDOWN_SECONDS = 3; public static int COUNTDOWN_SECONDS = 3;
public static HashMap<Integer, String> COUNTDOWN_TITLES = new HashMap<>(); public static HashMap<Integer, String> COUNTDOWN_TITLES = new HashMap<>();
public static String COUNTDOWN_SUBTITLE = "<gray>Preparing teleportation</gray>"; public static String COUNTDOWN_SUBTITLE = "<dark_grey>Preparing teleportation</dark_grey>";
// Messages
public static String MSG_TELEPORT_START = "<green>Starting teleport countdown...</green>";
public static String MSG_TELEPORT_SUCCESS = "<gold>You have arrived at a random plot!</gold>";
public static String MSG_TELEPORT_CANCELLED = "<red>Teleport cancelled! You moved.</red>";
public static String MSG_NO_PLOTS_FOUND = "<red>No plots found in this world.</red>";
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static void load() { private static void load() {
PORT_COMMAND = config.getString(prefix, "port-command", PORT_COMMAND);
ALLOWED_WORLDS = config.getStringList(prefix, "allowed-worlds", ALLOWED_WORLDS); ALLOWED_WORLDS = config.getStringList(prefix, "allowed-worlds", ALLOWED_WORLDS);
USE_LUCKPERMS = config.getBoolean(prefix + "permissions.", "use-luckperms", USE_LUCKPERMS);
LUCKPERMS_GROUP = config.getString(prefix + "permissions.", "luckperms-group", LUCKPERMS_GROUP);
USE_VAULT = config.getBoolean(prefix + "permissions.", "use-vault", USE_VAULT);
VAULT_GROUP = config.getString(prefix + "permissions.", "vault-group", VAULT_GROUP);
FALLBACK_PERM = config.getString(prefix + "permissions.", "fallback-perm", FALLBACK_PERM);
COUNTDOWN_SECONDS = config.getInt(prefix + "countdown.", "seconds", COUNTDOWN_SECONDS); COUNTDOWN_SECONDS = config.getInt(prefix + "countdown.", "seconds", COUNTDOWN_SECONDS);
COUNTDOWN_SUBTITLE = config.getString(prefix + "countdown.", "subtitle", COUNTDOWN_SUBTITLE); COUNTDOWN_SUBTITLE = config.getString(prefix + "countdown.", "subtitle", COUNTDOWN_SUBTITLE);
@ -157,22 +137,18 @@ import java.util.Set;
try { try {
COUNTDOWN_TITLES.put(Integer.parseInt(key), COUNTDOWN_TITLES.put(Integer.parseInt(key),
titlesSection.getString(key, key)); titlesSection.getString(key, key));
} catch (NumberFormatException ignored) {} } catch (NumberFormatException ignored) {
log.warn("Invalid countdown title key: {}", key);
}
} }
} else { } else {
// Write defaults on first run config.yaml.addDefault("random-plot.countdown.titles.3", "<color:#08FBFF>Go!");
config.yaml.addDefault("random-plot.countdown.titles.3", "<#08FBFF>3"); config.yaml.addDefault("random-plot.countdown.titles.2", "<color:#08FBFF>2");
config.yaml.addDefault("random-plot.countdown.titles.2", "<#08FBFF>2"); config.yaml.addDefault("random-plot.countdown.titles.1", "<color:#08FBFF>1");
config.yaml.addDefault("random-plot.countdown.titles.1", "<#08FBFF>1"); COUNTDOWN_TITLES.put(3, "<color:#08FBFF>2");
COUNTDOWN_TITLES.put(3, "<#08FBFF>3"); COUNTDOWN_TITLES.put(2, "<color:#08FBFF>1");
COUNTDOWN_TITLES.put(2, "<#08FBFF>2"); COUNTDOWN_TITLES.put(1, "<color:#08FBFF>Go!");
COUNTDOWN_TITLES.put(1, "<#08FBFF>1"); }
}
MSG_TELEPORT_START = config.getString(prefix + "messages.", "teleport-start", MSG_TELEPORT_START);
MSG_TELEPORT_SUCCESS = config.getString(prefix + "messages.", "teleport-success", MSG_TELEPORT_SUCCESS);
MSG_TELEPORT_CANCELLED = config.getString(prefix + "messages.", "teleport-cancelled", MSG_TELEPORT_CANCELLED);
MSG_NO_PLOTS_FOUND = config.getString(prefix + "messages.", "no-plots-found", MSG_NO_PLOTS_FOUND);
} }
} }
} }

View File

@ -1,7 +1,5 @@
package com.alttd.playerutils.config; package com.alttd.playerutils.config;
import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
@ -35,7 +33,7 @@ public class Messages extends AbstractConfig {
public static String KEY = "<green>Receive a key that you are owed: <gold>/pu key</gold></green>"; public static String KEY = "<green>Receive a key that you are owed: <gold>/pu key</gold></green>";
public static String GHAST_SPEED = "<green>Set the speed of a ghast: <gold>/pu ghastspeed <speed></gold></green>"; public static String GHAST_SPEED = "<green>Set the speed of a ghast: <gold>/pu ghastspeed <speed></gold></green>";
public static String RECOUNT_ARMOR_STANDS = "<green>Recount armor stands in current chunk: <gold>/pu recount</gold></green>"; public static String RECOUNT_ARMOR_STANDS = "<green>Recount armor stands in current chunk: <gold>/pu recount</gold></green>";
public static String RPP = "<green>Teleport to a random plot: <gold>/pu rpp</gold></green>"; public static String RANDOM_PLOT = "<green>Get a random plot: <gold>/pu randomplot</gold></green>";
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static void load() { private static void load() {
@ -48,7 +46,6 @@ public class Messages extends AbstractConfig {
ROTATE_BLOCK = config.getString(prefix, "rotate-block", ROTATE_BLOCK); ROTATE_BLOCK = config.getString(prefix, "rotate-block", ROTATE_BLOCK);
GHAST_SPEED = config.getString(prefix, "ghast-speed", GHAST_SPEED); GHAST_SPEED = config.getString(prefix, "ghast-speed", GHAST_SPEED);
RECOUNT_ARMOR_STANDS = config.getString(prefix, "recount-armor-stands", RECOUNT_ARMOR_STANDS); RECOUNT_ARMOR_STANDS = config.getString(prefix, "recount-armor-stands", RECOUNT_ARMOR_STANDS);
RPP = config.getString(prefix, "rpp", RPP);
} }
} }
@ -187,19 +184,6 @@ public class Messages extends AbstractConfig {
} }
public static class RANDOM_PLOT_PORT {
private static final String prefix = "pu-command.rpp.";
public static String NOT_ALLOWED_WORLD = "<red>You must be in an allowed world to use this command.</red>";
public static String PLOTSQUARED_UNAVAILABLE = "<red>PlotSquared is not available on this server.</red>";
@SuppressWarnings("unused")
private static void load() {
NOT_ALLOWED_WORLD = config.getString(prefix, "not-allowed-world", NOT_ALLOWED_WORLD);
PLOTSQUARED_UNAVAILABLE = config.getString(prefix, "plotsquared-unavailable", PLOTSQUARED_UNAVAILABLE);
}
}
public static class RECOUNT_ARMOR_STANDS { public static class RECOUNT_ARMOR_STANDS {
private static final String prefix = "recount-armor-stands."; private static final String prefix = "recount-armor-stands.";
@ -213,6 +197,7 @@ public class Messages extends AbstractConfig {
} }
} }
public static class VILLAGER_WORKSTATION { public static class VILLAGER_WORKSTATION {
private static final String prefix = "villager-workstation."; private static final String prefix = "villager-workstation.";
@ -225,4 +210,25 @@ public class Messages extends AbstractConfig {
NO_WORKSTATION = config.getString(prefix, "no-workstation", NO_WORKSTATION); NO_WORKSTATION = config.getString(prefix, "no-workstation", NO_WORKSTATION);
} }
} }
public static class RANDOM_PLOT {
private static final String prefix = "random-plot.";
public static String WORLD_NOT_ALLOWED = "<red>You must be in an allowed world to use this command.</red>";
public static String PLOT_SQUARED_NOT_ENABLED = "<red>PlotSquared is not available on this server.</red>";
public static String TELEPORT_START = "<green>Starting teleport countdown...</green>";
public static String TELEPORT_SUCCESS = "<gold>You have arrived at <plot_id> by <plot_owner> random plot!</gold>";
public static String TELEPORT_CANCELLED = "<red>Teleport cancelled! You moved.</red>";
public static String NO_PLOTS_FOUND = "<red>No plots found in this world.</red>";
@SuppressWarnings("unused")
private static void load() {
WORLD_NOT_ALLOWED = config.getString(prefix, "world-not-allowed", WORLD_NOT_ALLOWED);
PLOT_SQUARED_NOT_ENABLED = config.getString(prefix, "plotsquared-not-enabled", PLOT_SQUARED_NOT_ENABLED);
TELEPORT_START = config.getString(prefix, "teleport-start", TELEPORT_START);
TELEPORT_SUCCESS = config.getString(prefix, "teleport-success", TELEPORT_SUCCESS);
TELEPORT_CANCELLED = config.getString(prefix, "teleport-cancelled", TELEPORT_CANCELLED);
NO_PLOTS_FOUND = config.getString(prefix, "no-plots-found", NO_PLOTS_FOUND);
}
}
} }

View File

@ -38,7 +38,7 @@ public class VillagerWorkstationEvent implements Listener {
} }
private void showWorkstation(Player player, Villager villager) { private void showWorkstation(Player player, Villager villager) {
String professionName = formatName(villager.getProfession().name()); String professionName = formatName(villager.getProfession().key().asMinimalString());
Location jobSite = villager.getMemory(MemoryKey.JOB_SITE); Location jobSite = villager.getMemory(MemoryKey.JOB_SITE);
if (jobSite == null) { if (jobSite == null) {
@ -73,7 +73,7 @@ public class VillagerWorkstationEvent implements Listener {
double angle = (2 * Math.PI * i) / count; double angle = (2 * Math.PI * i) / count;
double x = cx + 0.5 * Math.cos(angle); double x = cx + 0.5 * Math.cos(angle);
double z = cz + 0.5 * Math.sin(angle); double z = cz + 0.5 * Math.sin(angle);
player.spawnParticle(Particle.VILLAGER_HAPPY, x, cy, z, 1, 0, 0, 0, 0); player.spawnParticle(Particle.HAPPY_VILLAGER, x, cy, z, 1, 0, 0, 0, 0);
} }
} }