Compare commits
2 Commits
master
...
april_fool
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c66ac7cc8 | ||
|
|
592f58a89b |
|
|
@ -1,6 +1,7 @@
|
||||||
package com.alttd.playerutils;
|
package com.alttd.playerutils;
|
||||||
|
|
||||||
import com.alttd.playerutils.commands.PlayerUtilsCommand;
|
import com.alttd.playerutils.commands.PlayerUtilsCommand;
|
||||||
|
import com.alttd.playerutils.commands.playerutils_subcommands.AprilFools;
|
||||||
import com.alttd.playerutils.commands.playerutils_subcommands.GhastSpeed;
|
import com.alttd.playerutils.commands.playerutils_subcommands.GhastSpeed;
|
||||||
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;
|
||||||
|
|
@ -13,12 +14,17 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.alttd.playerutils.util.AprilFoolsPrank;
|
||||||
|
|
||||||
public final class PlayerUtils extends JavaPlugin {
|
public final class PlayerUtils extends JavaPlugin {
|
||||||
|
|
||||||
private PlayerUtilsCommand playerUtilsCommand;
|
private PlayerUtilsCommand playerUtilsCommand;
|
||||||
|
private AprilFoolsPrank aprilFoolsPrank;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
// initialize prank utility
|
||||||
|
aprilFoolsPrank = new AprilFoolsPrank(this);
|
||||||
registerCommands();
|
registerCommands();
|
||||||
registerEvents();
|
registerEvents();
|
||||||
reloadConfigs();
|
reloadConfigs();
|
||||||
|
|
@ -32,6 +38,8 @@ public final class PlayerUtils extends JavaPlugin {
|
||||||
|
|
||||||
private void registerCommands() {
|
private void registerCommands() {
|
||||||
playerUtilsCommand = new PlayerUtilsCommand(this);
|
playerUtilsCommand = new PlayerUtilsCommand(this);
|
||||||
|
// add april fools test command
|
||||||
|
playerUtilsCommand.addSubCommand(new AprilFools(aprilFoolsPrank));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerEvents() {
|
private void registerEvents() {
|
||||||
|
|
@ -61,7 +69,11 @@ public final class PlayerUtils extends JavaPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerSchedulers() {
|
private void registerSchedulers() {
|
||||||
|
// periodic key storage save (async)
|
||||||
Bukkit.getScheduler().runTaskTimerAsynchronously(this, KeyStorage.STORAGE::save,
|
Bukkit.getScheduler().runTaskTimerAsynchronously(this, KeyStorage.STORAGE::save,
|
||||||
TimeUnit.MINUTES.toSeconds(5) * 20, TimeUnit.MINUTES.toSeconds(5) * 20);
|
TimeUnit.MINUTES.toSeconds(5) * 20, TimeUnit.MINUTES.toSeconds(5) * 20);
|
||||||
|
|
||||||
|
// April 1st prank scheduler
|
||||||
|
aprilFoolsPrank.schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.alttd.playerutils.commands.playerutils_subcommands;
|
||||||
|
|
||||||
|
import com.alttd.playerutils.commands.SubCommand;
|
||||||
|
import com.alttd.playerutils.config.Messages;
|
||||||
|
import com.alttd.playerutils.util.AprilFoolsPrank;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AprilFools extends SubCommand {
|
||||||
|
|
||||||
|
private final AprilFoolsPrank prank;
|
||||||
|
|
||||||
|
public AprilFools(AprilFoolsPrank prank) {
|
||||||
|
this.prank = prank;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender commandSender, String[] args) {
|
||||||
|
if (!(commandSender instanceof Player player)) {
|
||||||
|
commandSender.sendRichMessage(Messages.GENERIC.PLAYER_ONLY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
boolean ok = prank.playSoundAroundPlayer(player);
|
||||||
|
if (ok) {
|
||||||
|
commandSender.sendRichMessage("<green>April Fools test triggered. Listen closely...");
|
||||||
|
} else {
|
||||||
|
commandSender.sendRichMessage("<red>Failed to trigger. You must be in the overworld named 'world'.");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "aprilfools";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getTabComplete(CommandSender commandSender, String[] args) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHelpMessage() {
|
||||||
|
return "<gray>/playerutils aprilfools</gray> <dark_gray>-</dark_gray> <gray>Play a fake explosion near you (testing).";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -42,7 +42,7 @@ import java.util.stream.Collectors;
|
||||||
.forEach(team -> team.removePlayer(player));
|
.forEach(team -> team.removePlayer(player));
|
||||||
|
|
||||||
if (args[1].equalsIgnoreCase("off")) {
|
if (args[1].equalsIgnoreCase("off")) {
|
||||||
turnOffGlow(commandSender, player, otherPlayer, board);
|
turnOffGlow(commandSender, player, otherPlayer);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,15 +88,10 @@ import java.util.stream.Collectors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void turnOffGlow(CommandSender commandSender, Player player, boolean otherPlayer, Scoreboard board) {
|
private void turnOffGlow(CommandSender commandSender, Player player, boolean otherPlayer) {
|
||||||
player.sendRichMessage(Messages.GLOW.GLOW_OFF);
|
player.sendRichMessage(Messages.GLOW.GLOW_OFF);
|
||||||
player.setGlowing(false);
|
player.setGlowing(false);
|
||||||
|
|
||||||
board.getTeams().stream()
|
|
||||||
.filter(team -> team.getName().startsWith("Glow-"))
|
|
||||||
.filter(team -> team.hasPlayer(player))
|
|
||||||
.forEach(team -> team.removePlayer(player));
|
|
||||||
|
|
||||||
if (otherPlayer) {
|
if (otherPlayer) {
|
||||||
commandSender.sendRichMessage(Messages.GLOW.GLOW_OFF_FOR_PLAYER, Placeholder.component("player", player.name()));
|
commandSender.sendRichMessage(Messages.GLOW.GLOW_OFF_FOR_PLAYER, Placeholder.component("player", player.name()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ public class BookByteLimitListener implements Listener {
|
||||||
|
|
||||||
private boolean isOversizedBook(ItemStack stack) {
|
private boolean isOversizedBook(ItemStack stack) {
|
||||||
boolean isOversizedBook = BookByteUtils.shouldCountForBookByteLimit(stack)
|
boolean isOversizedBook = BookByteUtils.shouldCountForBookByteLimit(stack)
|
||||||
&& BookByteUtils.computeBytes(stack) > BookByteUtils.getMAX_BOOK_BYTES();
|
&& BookByteUtils.computeBytes(stack) > BookByteUtils.MAX_BOOK_BYTES;
|
||||||
if (isOversizedBook) {
|
if (isOversizedBook) {
|
||||||
log.warn("Player tried to drop an oversized book");
|
log.warn("Player tried to drop an oversized book");
|
||||||
Component message = MiniMessage.miniMessage().deserialize(
|
Component message = MiniMessage.miniMessage().deserialize(
|
||||||
|
|
@ -35,7 +35,7 @@ public class BookByteLimitListener implements Listener {
|
||||||
|
|
||||||
private boolean isOversizedBook(ItemStack stack, HumanEntity humanEntity) {
|
private boolean isOversizedBook(ItemStack stack, HumanEntity humanEntity) {
|
||||||
boolean isOversizedBook = BookByteUtils.shouldCountForBookByteLimit(stack)
|
boolean isOversizedBook = BookByteUtils.shouldCountForBookByteLimit(stack)
|
||||||
&& BookByteUtils.computeBytes(stack) > BookByteUtils.getMaxBookBytes(humanEntity);
|
&& BookByteUtils.computeBytes(stack) > BookByteUtils.MAX_BOOK_BYTES;
|
||||||
if (isOversizedBook) {
|
if (isOversizedBook) {
|
||||||
log.warn("{} [{}] tried to drop an oversized book", humanEntity.getName(), humanEntity.getUniqueId());
|
log.warn("{} [{}] tried to drop an oversized book", humanEntity.getName(), humanEntity.getUniqueId());
|
||||||
Component message = MiniMessage.miniMessage().deserialize(
|
Component message = MiniMessage.miniMessage().deserialize(
|
||||||
|
|
@ -96,9 +96,7 @@ public class BookByteLimitListener implements Listener {
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryMoveItem(InventoryMoveItemEvent event) {
|
public void onInventoryMoveItem(InventoryMoveItemEvent event) {
|
||||||
if (event.getSource().getHolder() instanceof HumanEntity humanEntity && isOversizedBook(event.getItem(), humanEntity)) {
|
if (isOversizedBook(event.getItem())) {
|
||||||
event.setCancelled(true);
|
|
||||||
} else if (isOversizedBook(event.getItem())) {
|
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ public class BookWriteEvent implements Listener {
|
||||||
|
|
||||||
int totalBytes = BookByteUtils.computeBytes(meta);
|
int totalBytes = BookByteUtils.computeBytes(meta);
|
||||||
|
|
||||||
if (totalBytes > BookByteUtils.getMaxBookBytes(player)) {
|
if (totalBytes > BookByteUtils.MAX_BOOK_BYTES) {
|
||||||
log.warn("Player {} [{}] tried to write a book with {} bytes",
|
log.warn("Player {} [{}] tried to write a book with {} bytes",
|
||||||
player.getName(), player.getUniqueId(), totalBytes);
|
player.getName(), player.getUniqueId(), totalBytes);
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
|
|
@ -31,7 +31,7 @@ public class BookWriteEvent implements Listener {
|
||||||
"<red>Player <player> tried to write a book with <bytes> bytes</red>",
|
"<red>Player <player> tried to write a book with <bytes> bytes</red>",
|
||||||
Placeholder.unparsed("player", player.getName()), Placeholder.parsed("bytes", String.valueOf(totalBytes)));
|
Placeholder.unparsed("player", player.getName()), Placeholder.parsed("bytes", String.valueOf(totalBytes)));
|
||||||
Bukkit.broadcast(message, "staffutils.patrol");
|
Bukkit.broadcast(message, "staffutils.patrol");
|
||||||
} else if (totalBytes > BookByteUtils.getBigBookBytes(player)) {
|
} else if (totalBytes > BookByteUtils.BIG_BOOK_BYTES) {
|
||||||
log.warn("Player {} [{}] wrote a large book with {} bytes",
|
log.warn("Player {} [{}] wrote a large book with {} bytes",
|
||||||
player.getName(), player.getUniqueId(), totalBytes);
|
player.getName(), player.getUniqueId(), totalBytes);
|
||||||
Component message = MiniMessage.miniMessage().deserialize(
|
Component message = MiniMessage.miniMessage().deserialize(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
package com.alttd.playerutils.util;
|
||||||
|
|
||||||
|
import com.alttd.playerutils.PlayerUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.Month;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates the April Fools' prank logic. - schedule(): registers the timed prank that only runs on April 1st and
|
||||||
|
* only during overworld night. - playExplosionAround(Player): immediately plays the explosion sound around the target
|
||||||
|
* for testing (no date/time checks), but still requires the target to be in the overworld named "world" to match
|
||||||
|
* intended environment.
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class AprilFoolsPrank {
|
||||||
|
|
||||||
|
private final PlayerUtils plugin;
|
||||||
|
|
||||||
|
public AprilFoolsPrank(PlayerUtils plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the timed prank task. Safe to call on the main thread during plugin enable.
|
||||||
|
*/
|
||||||
|
public void schedule() {
|
||||||
|
// April 1st prank: during overworld night, every 2 minutes pick one player and play an explosion somewhere in a 30-block radius
|
||||||
|
Bukkit.getScheduler().runTaskTimer(plugin, () -> {
|
||||||
|
LocalDate now = LocalDate.now(ZoneId.systemDefault());
|
||||||
|
if (now.getMonth() != Month.APRIL || now.getDayOfMonth() != 1) {
|
||||||
|
return; // only active on April 1st
|
||||||
|
}
|
||||||
|
|
||||||
|
World world = Bukkit.getWorld("world");
|
||||||
|
if (world == null) {
|
||||||
|
return; // overworld not present
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Player> players = world.getPlayers();
|
||||||
|
if (players.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player target = players.get(ThreadLocalRandom.current().nextInt(players.size()));
|
||||||
|
playOnce(world, target);
|
||||||
|
}, 20L, 20L * 60L * 2L); // start after 1s, repeat every 2 minutes
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger the prank once around the given player for testing. Returns true if executed. This method ignores the
|
||||||
|
* date and time checks so it can be tested easily, but it still requires the player to be in the overworld named
|
||||||
|
* "world".
|
||||||
|
*/
|
||||||
|
public boolean playSoundAroundPlayer(Player target) {
|
||||||
|
if (target == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
World world = target.getWorld();
|
||||||
|
if (!"world".equalsIgnoreCase(world.getName())) {
|
||||||
|
return false; // only intended for overworld
|
||||||
|
}
|
||||||
|
playOnce(world, target);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Sound> getSounds() {
|
||||||
|
return List.of(Sound.ENTITY_GENERIC_EXPLODE, Sound.BLOCK_BELL_USE, Sound.ENTITY_SPIDER_AMBIENT,
|
||||||
|
Sound.ENTITY_TNT_PRIMED, Sound.ENTITY_CAT_BEG_FOR_FOOD, Sound.ENTITY_SHULKER_AMBIENT,
|
||||||
|
Sound.BLOCK_WOODEN_DOOR_CLOSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playOnce(World world, Player target) {
|
||||||
|
Location base = target.getLocation();
|
||||||
|
double radius = 25.0;
|
||||||
|
double r = ThreadLocalRandom.current().nextDouble(radius);
|
||||||
|
double theta = ThreadLocalRandom.current().nextDouble(Math.PI * 2);
|
||||||
|
double dx = r * Math.cos(theta);
|
||||||
|
double dz = r * Math.sin(theta);
|
||||||
|
Location soundLoc = new Location(world, base.getX() + dx, base.getY(), base.getZ() + dz);
|
||||||
|
List<Sound> sounds = getSounds();
|
||||||
|
Sound chosen = sounds.get(ThreadLocalRandom.current().nextInt(sounds.size()));
|
||||||
|
log.info("Playing sound {} at {} (for {})", chosen, soundLoc, target.getName());
|
||||||
|
world.playSound(soundLoc, chosen, 1f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
package com.alttd.playerutils.util;
|
package com.alttd.playerutils.util;
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.ShulkerBox;
|
import org.bukkit.block.ShulkerBox;
|
||||||
import org.bukkit.entity.HumanEntity;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.BookMeta;
|
import org.bukkit.inventory.meta.BookMeta;
|
||||||
import org.bukkit.inventory.meta.BlockStateMeta;
|
import org.bukkit.inventory.meta.BlockStateMeta;
|
||||||
|
|
@ -22,30 +19,8 @@ public final class BookByteUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 65,000 bytes per book (below CoreProtect hard limit ~65,535)
|
// 65,000 bytes per book (below CoreProtect hard limit ~65,535)
|
||||||
@Getter
|
public static final int MAX_BOOK_BYTES = 30_000;
|
||||||
private static final int MAX_BOOK_BYTES = 30_000;
|
public static final int BIG_BOOK_BYTES = 10_000;
|
||||||
@Getter
|
|
||||||
private static final int BIG_BOOK_BYTES = 10_000;
|
|
||||||
|
|
||||||
public static int getBigBookBytes(HumanEntity humanEntity) {
|
|
||||||
return calcBookBytes(humanEntity, BIG_BOOK_BYTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getMaxBookBytes(HumanEntity humanEntity) {
|
|
||||||
return calcBookBytes(humanEntity, MAX_BOOK_BYTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int calcBookBytes(HumanEntity humanEntity, int bookBytes) {
|
|
||||||
if (humanEntity.hasPermission("playerutils.bigbook.bypass")) {
|
|
||||||
return Integer.MAX_VALUE;
|
|
||||||
} else if (humanEntity.hasPermission("playerutils.bigbook.double")) {
|
|
||||||
return bookBytes * 2;
|
|
||||||
} else if (humanEntity.hasPermission("playerutils.bigbook.quadruple")) {
|
|
||||||
return bookBytes * 4;
|
|
||||||
} else {
|
|
||||||
return bookBytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean shouldCountForBookByteLimit(ItemStack stack) {
|
public static boolean shouldCountForBookByteLimit(ItemStack stack) {
|
||||||
if (stack == null) {
|
if (stack == null) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user