Replaced jail head skript, fixed TrimManager bugs and added update to admin utils.

This commit is contained in:
wolf
2025-07-01 11:00:03 -04:00
parent 0402d95f56
commit 8de734e033
8 changed files with 237 additions and 130 deletions

View File

@@ -40,6 +40,7 @@ public class Manager {
trimManager.register(new NetheriteAnimation()); trimManager.register(new NetheriteAnimation());
trimManager.register(new QuartzAnimation()); trimManager.register(new QuartzAnimation());
trimManager.register(new RedstoneAnimation()); trimManager.register(new RedstoneAnimation());
trimManager.register();
trimManager.startTicking(); trimManager.startTicking();
} }

View File

@@ -74,16 +74,12 @@ public class AdminCommand implements QuickCommand, Data {
) )
) )
).then( ).then(
b.arg("update") b.arg("update","reload","cleanup")
).then(
b.arg("reload")
).then(
b.arg("cleanup")
); );
} }
private void handleUpdate(CommandSender sender, Args args) { private void handleUpdate(CommandSender sender, Args args) {
infoAny(sender,"Checking for an updated..."); infoAny(sender,"Checking for an update...");
Bukkit.getScheduler().runTask(main.getPlugin(),()->{ Bukkit.getScheduler().runTask(main.getPlugin(),()->{
if (AutoUpdater.checkUpdate(main.getPlugin(),main.getCommon())) { if (AutoUpdater.checkUpdate(main.getPlugin(),main.getCommon())) {
successAny(sender,"Updated plugin has been downloaded to {0}.","plugins/update"); successAny(sender,"Updated plugin has been downloaded to {0}.","plugins/update");
@@ -108,7 +104,7 @@ public class AdminCommand implements QuickCommand, Data {
} }
} }
} }
if (count > 0) successAny(sender,"Successfully removed {0} temporary entities."); if (count > 0) successAny(sender,"Successfully removed {0} temporary entities.",count);
else errorAny(sender,"Could not find any temporary entities."); else errorAny(sender,"Could not find any temporary entities.");
}); });
} }

View File

@@ -17,6 +17,7 @@ public class FreezeEvents implements QuickListener {
public void onMove(PlayerMoveEvent e) { public void onMove(PlayerMoveEvent e) {
Freeze.FrozenPlayer frozen = Freeze.getFrozen().get(e.getPlayer().getUniqueId()); Freeze.FrozenPlayer frozen = Freeze.getFrozen().get(e.getPlayer().getUniqueId());
if (frozen == null) return; if (frozen == null) return;
if (frozen.movementAllowed()) return;
if (!e.getFrom().toVector().equals(e.getTo().toVector())) { if (!e.getFrom().toVector().equals(e.getTo().toVector())) {
e.setTo(e.getFrom()); e.setTo(e.getFrom());
@@ -37,6 +38,7 @@ public class FreezeEvents implements QuickListener {
public void onCommand(PlayerCommandPreprocessEvent e) { public void onCommand(PlayerCommandPreprocessEvent e) {
Freeze.FrozenPlayer frozen = Freeze.getFrozen().get(e.getPlayer().getUniqueId()); Freeze.FrozenPlayer frozen = Freeze.getFrozen().get(e.getPlayer().getUniqueId());
if (frozen == null) return; if (frozen == null) return;
if (frozen.commandsAllowed()) return;
String baseCmd = e.getMessage().replace("/", "").split(" ")[0].toLowerCase(); String baseCmd = e.getMessage().replace("/", "").split(" ")[0].toLowerCase();
if (!Data.data.getConfig().allowedFreezeCommands.contains(baseCmd)) { if (!Data.data.getConfig().allowedFreezeCommands.contains(baseCmd)) {
@@ -50,6 +52,7 @@ public class FreezeEvents implements QuickListener {
if (!(e.getEntity() instanceof Player p)) return; if (!(e.getEntity() instanceof Player p)) return;
Freeze.FrozenPlayer frozen = Freeze.getFrozen().get(p.getUniqueId()); Freeze.FrozenPlayer frozen = Freeze.getFrozen().get(p.getUniqueId());
if (frozen == null) return; if (frozen == null) return;
if (frozen.damageAllowed()) return;
e.setCancelled(true); e.setCancelled(true);
if (frozen.getOnMove() != null) frozen.getOnMove().accept(p); if (frozen.getOnMove() != null) frozen.getOnMove().accept(p);
@@ -60,6 +63,7 @@ public class FreezeEvents implements QuickListener {
if (!(e.getEntity() instanceof Player p)) return; if (!(e.getEntity() instanceof Player p)) return;
Freeze.FrozenPlayer frozen = Freeze.getFrozen().get(p.getUniqueId()); Freeze.FrozenPlayer frozen = Freeze.getFrozen().get(p.getUniqueId());
if (frozen == null) return; if (frozen == null) return;
if (frozen.damageAllowed()) return;
e.setCancelled(true); e.setCancelled(true);
if (frozen.getOnMove() != null) frozen.getOnMove().accept(p); if (frozen.getOnMove() != null) frozen.getOnMove().accept(p);

View File

@@ -48,6 +48,9 @@ public class Freeze {
private final Location backLocation; private final Location backLocation;
private final Consumer<OfflinePlayer> onQuit; private final Consumer<OfflinePlayer> onQuit;
private final Consumer<Player> onMove; private final Consumer<Player> onMove;
private boolean allowMovement = false;
private boolean allowDamage = false;
private boolean allowCommands = false;
public FrozenPlayer(UUID uuid, Location backLocation, Consumer<OfflinePlayer> onQuit, Consumer<Player> onMove) { public FrozenPlayer(UUID uuid, Location backLocation, Consumer<OfflinePlayer> onQuit, Consumer<Player> onMove) {
this.uuid = uuid; this.uuid = uuid;
@@ -73,5 +76,29 @@ public class Freeze {
if (player == null) return; if (player == null) return;
player.teleport(backLocation); player.teleport(backLocation);
} }
public void setAllowDamage(boolean allowDamage) {
this.allowDamage = allowDamage;
}
public void setAllowMovement(boolean allowMovement) {
this.allowMovement = allowMovement;
}
public boolean commandsAllowed() {
return allowCommands;
}
public void setAllowCommands(boolean allowCommands) {
this.allowCommands = allowCommands;
}
public boolean damageAllowed() {
return allowDamage;
}
public boolean movementAllowed() {
return allowMovement;
}
} }
} }

View File

@@ -4,45 +4,96 @@ import me.trouper.alias.server.events.QuickListener;
import me.trouper.alias.server.systems.AbstractWand; import me.trouper.alias.server.systems.AbstractWand;
import me.trouper.alias.server.systems.world.Snapshot; import me.trouper.alias.server.systems.world.Snapshot;
import me.trouper.alias.utils.ItemBuilder; import me.trouper.alias.utils.ItemBuilder;
import me.trouper.alias.utils.TargetingUtils;
import me.trouper.clonedupecore.server.punishment.Freeze;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.util.BoundingBox;
import java.util.ArrayList; import java.util.HashMap;
import java.util.List; import java.util.Map;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
public class JailHeadWand extends AbstractWand implements QuickListener { public class JailHeadWand extends AbstractWand implements QuickListener {
public JailHeadWand() { public JailHeadWand() {
super("clonedupe.jailwand", ItemBuilder.of(Material.PLAYER_HEAD) super("clonedupe.jailwand", ItemBuilder.of(Material.PLAYER_HEAD)
.createCustomHead("http://textures.minecraft.net/texture/a63b87ee6a55f2bf0135b26bd96ec279eded175f948c036d88a60725e127371c","Port-a-Jail")
.loreComponent(Component.text("Right click to use on a player!", NamedTextColor.GRAY).decoration(TextDecoration.ITALIC,false))
.build()); .build());
} }
private final Map<UUID,Jail> jailed = new HashMap<>();
@Override @Override
protected void onRightClick(Player player) { protected void onRightClick(Player player) {
Optional<LivingEntity> optional = TargetingUtils.livingClosestAngle(player.getEyeLocation(),player.getEyeLocation().getDirection(),10,0.5);
if (optional.isEmpty() || !(optional.get() instanceof Player target)) return;
if (jailed.containsKey(target.getUniqueId())) {
Freeze.thawPlayer(target.getUniqueId());
jailed.remove(target.getUniqueId()).revertCage();
return;
}
Freeze.quickFreeze(target);
Freeze.FrozenPlayer fp = new Freeze.FrozenPlayer(target.getUniqueId(),target.getLocation().clone(),null,null);
fp.setAllowMovement(true);
Freeze.freezePlayer(fp);
Jail jail = new Jail(target);
jail.createCage();
jailed.put(target.getUniqueId(),jail);
} }
private class Jail { private class Jail {
private final UUID prisoner; private final UUID prisoner;
private final List<Snapshot> changedBlocks = new ArrayList<>(); private final Map<Block, Snapshot> snapshots = new HashMap<>();
public Jail(Player prisoner) { public Jail(Player prisoner) {
this.prisoner = prisoner.getUniqueId(); this.prisoner = prisoner.getUniqueId();
Location loc = prisoner.getLocation(); }
public void createCage() {
Player p = Bukkit.getPlayer(prisoner);
if (p == null) return;
Location loc = p.getLocation().clone().subtract(0,1,0);
final int x = loc.getBlockX(); final int x = loc.getBlockX();
final int y = loc.getBlockY(); final int y = loc.getBlockY();
final int z = loc.getBlockZ(); final int z = loc.getBlockZ();
for (int dx = x - 1; dx < x + 1; dx++) {
for (int dy = y - 1; dy < y + 2; dy++) { for (int dx = -1; dx <= 1; dx++) {
for (int dz = z - 1; dz < z + 1; dz++) { for (int dy = 0; dy <= 3; dy++) {
Location pointer = loc.clone(); for (int dz = -1; dz <= 1; dz++) {
pointer.setX(dx); int bx = x + dx;
pointer.setY(dy); int by = y + dy;
pointer.setZ(dz); int bz = z + dz;
Location blockLoc = new Location(loc.getWorld(), bx, by, bz);
Block block = blockLoc.getBlock();
snapshots.put(block, new Snapshot(block));
if (dy == 0 || dy == 3) {
block.setType(Material.IRON_BLOCK);
} else if (dy == 1 || dy == 2) {
if (Math.abs(dx) == 1 || Math.abs(dz) == 1) {
block.setType(Material.IRON_BARS);
} else {
block.setType(Material.AIR);
} }
} }
} }
} }
} }
} }
public void revertCage() {
snapshots.forEach((block,snapshot) -> snapshot.restore(block));
}
}
}

View File

@@ -1,138 +1,132 @@
package me.trouper.clonedupecore.server.trims; package me.trouper.clonedupecore.server.trims;
import me.trouper.alias.server.Main;
import me.trouper.alias.server.events.QuickListener; import me.trouper.alias.server.events.QuickListener;
import me.trouper.alias.server.events.Registrar;
import me.trouper.alias.server.systems.Verbose;
import me.trouper.clonedupecore.data.Data; import me.trouper.clonedupecore.data.Data;
import me.trouper.clonedupecore.utils.ArmorUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ArmorMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.trim.ArmorTrim;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Registrar(exclude = true)
public class TrimManager implements QuickListener, Data { public class TrimManager implements QuickListener, Data {
private final Map<ValidMaterial, MaterialAnimation> animations = new EnumMap<>(ValidMaterial.class);
private final Map<UUID, ActiveTrim> activePlayers = new HashMap<>();
private final Set<MaterialAnimation> allAnimations = new HashSet<>();
private final Map<UUID, MovementTracker> trackerMap = new HashMap<>();
private final ConcurrentHashMap<UUID, MaterialAnimation> lastAnimationMap = new ConcurrentHashMap<>();
private final Set<UUID> isStationary = new HashSet<>();
public void register(MaterialAnimation animation) { public void register(MaterialAnimation animation) {
animations.put(animation.getMaterial(), animation); allAnimations.add(animation);
}
public void tickPlayer(Player player) {
UUID uuid = player.getUniqueId();
if (shouldHide(player)) {
safeRemove(player);
return;
}
ValidMaterial currentMaterial = getActiveMaterial(player);
ActiveTrim active = activePlayers.get(uuid);
Location currentLocation = player.getLocation();
if (currentMaterial == null) {
safeRemove(player);
return;
}
if (active != null && active.material == currentMaterial) {
active.ticks++;
if (active.lastCheckedLocation != null && active.lastCheckedLocation.getWorld().equals(currentLocation.getWorld()) && currentLocation.distanceSquared(active.lastCheckedLocation) > 0.001) {
active.lastMoveTimestamp = System.currentTimeMillis();
}
active.lastCheckedLocation = currentLocation;
} else {
active = new ActiveTrim(currentMaterial, currentLocation);
safeRemove(player);
activePlayers.put(uuid, active);
}
MaterialAnimation animation = animations.get(currentMaterial);
if (animation != null) {
long loopTime = active.ticks % animation.getLoopDuration();
long timeSinceLastMove = System.currentTimeMillis() - active.lastMoveTimestamp;
if (timeSinceLastMove < 1000) {
animation.onRemove(player);
animation.tickMoving(player, getViewers(player), loopTime);
} else {
animation.tickStationary(player, getViewers(player), loopTime);
}
}
}
public void safeRemove(OfflinePlayer player) {
UUID id = player.getUniqueId();
if (activePlayers.containsKey(id)) animations.get(activePlayers.get(id).material).onRemove(player);
activePlayers.remove(id);
} }
public void startTicking() { public void startTicking() {
Bukkit.getScheduler().runTaskTimer(main.getPlugin(), () -> Bukkit.getOnlinePlayers().forEach(this::tickPlayer),0,1); AtomicInteger globalTime = new AtomicInteger(0);
Bukkit.getScheduler().runTaskTimer(main.getPlugin(), () -> {
Bukkit.getOnlinePlayers().forEach(player->{
if (!player.isOnline()) return;
tickPlayer(player, globalTime.get());
});
globalTime.getAndIncrement();
}, 0, 1);
} }
private ValidMaterial getActiveMaterial(Player player) { public void tickPlayer(Player player, int globalTime) {
ItemStack[] armor = player.getInventory().getArmorContents(); UUID playerId = player.getUniqueId();
if (armor.length != 4) return null; MaterialAnimation activeAnimation = getAnimation(player);
if (!player.isOnline()) return;
if (activeAnimation == null && lastAnimationMap.containsKey(playerId)) {
MaterialAnimation lastAnimation = lastAnimationMap.remove(playerId);
Verbose.send("Player has no active animation, removing and stopping {0}, their last active animation.", lastAnimation.getMaterial().name());
lastAnimation.onRemove(player);
return;
}
ValidMaterial found = null; if (activeAnimation == null) {
for (ItemStack piece : armor) { return;
if (!ArmorUtils.isArmor(piece)) return null; } else if (lastAnimationMap.containsKey(playerId) && !lastAnimationMap.get(playerId).equals(activeAnimation)) {
lastAnimationMap.put(playerId,activeAnimation);
} else if (!lastAnimationMap.containsKey(playerId)) {
lastAnimationMap.put(playerId,activeAnimation);
}
ItemMeta meta = piece.getItemMeta(); MovementTracker tracker = trackerMap.computeIfAbsent(playerId,k -> new MovementTracker(player.getLocation()));
if (!(meta instanceof ArmorMeta armorMeta)) return null; long loopTime = globalTime % activeAnimation.getLoopDuration();
if (!armorMeta.hasTrim()) return null;
ArmorTrim trim = armorMeta.getTrim(); if (tracker.isStationary) {
if (trim == null) return null; isStationary.add(playerId);
activeAnimation.tickStationary(player,getViewers(player),loopTime);
} else {
if (isStationary.remove(playerId)) activeAnimation.onRemove(player);
activeAnimation.tickMoving(player,getViewers(player),loopTime);
}
ValidMaterial vm = ValidMaterial.validate(trim.getMaterial()); tracker.tick(player.getLocation());
if (vm == null) return null; }
if (found == null) { public static class MovementTracker {
found = vm; private Location lastLocation;
} else if (found != vm) { private long lastMovedTime;
private boolean isStationary;
public MovementTracker(Location currentLocation) {
lastMovedTime = System.currentTimeMillis();
isStationary = true;
lastLocation = currentLocation;
}
public void tick(Location currentLocation) {
long now = System.currentTimeMillis();
if (lastLocation.distanceSquared(currentLocation) > 0.01) {
lastMovedTime = now;
}
isStationary = (now - lastMovedTime) >= 1000;
lastLocation = currentLocation;
}
}
public MaterialAnimation getAnimation(Player player) {
ValidMaterial playerMaterial = ValidMaterial.getActiveMaterial(player);
if (playerMaterial == null) return null;
for (MaterialAnimation animation : allAnimations) {
if (animation.getMaterial().equals(playerMaterial)) return animation;
}
return null; return null;
} }
}
return found;
}
private boolean shouldHide(Player player) { private boolean shouldHide(Player player) {
return getStorage().disabledOwnParticles.contains(player.getUniqueId().toString()); return getStorage().disabledOwnParticles.contains(player.getUniqueId().toString());
} }
private Set<Player> getViewers(Player player) { private Set<Player> getViewers(Player player) {
if (shouldHide(player)) return new HashSet<>(); if (shouldHide(player)) {
return Bukkit.getOnlinePlayers().stream().filter(viewer-> !getStorage().disabledGlobalParticles.contains(viewer.getUniqueId().toString())).collect(Collectors.toSet()); return Collections.emptySet();
} }
private static class ActiveTrim { return Bukkit.getOnlinePlayers().stream()
final ValidMaterial material; .filter(viewer -> !getStorage().disabledGlobalParticles.contains(viewer.getUniqueId().toString()))
long ticks; .collect(Collectors.toSet());
long lastMoveTimestamp;
Location lastCheckedLocation;
ActiveTrim(ValidMaterial material, Location initialLocation) {
this.material = material;
this.ticks = 0;
this.lastMoveTimestamp = System.currentTimeMillis();
this.lastCheckedLocation = initialLocation;
}
} }
@EventHandler @EventHandler
public void onLeave(PlayerQuitEvent e) { public void onQuit(PlayerQuitEvent e) {
safeRemove(e.getPlayer()); Player player = e.getPlayer();
UUID playerId = player.getUniqueId();
Verbose.send("{0} has quit!",player.getName());
if (lastAnimationMap.containsKey(playerId)) {
MaterialAnimation lastAnimation = lastAnimationMap.get(playerId);
Verbose.send("Last animation for {0} is {1}.",player.getName(),lastAnimation.getMaterial().name());
lastAnimation.onRemove(player);
} else {
Verbose.send("{0} had no active animations.",player.getName());
}
} }
} }

View File

@@ -1,5 +1,11 @@
package me.trouper.clonedupecore.server.trims; package me.trouper.clonedupecore.server.trims;
import me.trouper.clonedupecore.utils.ArmorUtils;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ArmorMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.trim.ArmorTrim;
import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimMaterial;
public enum ValidMaterial { public enum ValidMaterial {
@@ -36,4 +42,34 @@ public enum ValidMaterial {
name = name.toUpperCase(); name = name.toUpperCase();
return ValidMaterial.valueOf(name).getCanonical(); return ValidMaterial.valueOf(name).getCanonical();
} }
public static ValidMaterial getActiveMaterial(Player player) {
ItemStack[] armor = player.getInventory().getArmorContents();
if (armor.length != 4) return null;
ValidMaterial trimMaterial = null;
for (ItemStack piece : armor) {
if (!ArmorUtils.isArmor(piece)) return null;
ItemMeta meta = piece.getItemMeta();
if (!(meta instanceof ArmorMeta armorMeta) || !armorMeta.hasTrim()) {
return null;
}
ArmorTrim trim = armorMeta.getTrim();
if (trim == null) return null;
ValidMaterial currentPieceMaterial = ValidMaterial.validate(trim.getMaterial());
if (currentPieceMaterial == null) return null;
if (trimMaterial == null) {
trimMaterial = currentPieceMaterial;
} else if (trimMaterial != currentPieceMaterial) {
return null;
}
}
return trimMaterial;
}
} }

View File

@@ -1,5 +1,6 @@
package me.trouper.clonedupecore.server.trims.animations; package me.trouper.clonedupecore.server.trims.animations;
import me.trouper.alias.server.systems.Verbose;
import me.trouper.alias.server.systems.visual.DisplayUtils; import me.trouper.alias.server.systems.visual.DisplayUtils;
import me.trouper.alias.server.systems.visual.ParticleUtils; import me.trouper.alias.server.systems.visual.ParticleUtils;
import me.trouper.clonedupecore.server.trims.MaterialAnimation; import me.trouper.clonedupecore.server.trims.MaterialAnimation;
@@ -43,6 +44,7 @@ public class NetheriteAnimation extends MaterialAnimation {
double angle = (loopTime / (double) LOOP_DURATION) * 2 * Math.PI; double angle = (loopTime / (double) LOOP_DURATION) * 2 * Math.PI;
List<BlockDisplay> displays = activeDisplays.computeIfAbsent(playerId, id -> { List<BlockDisplay> displays = activeDisplays.computeIfAbsent(playerId, id -> {
Verbose.send("{0} needed new BlockDisplays",player.getName());
List<BlockDisplay> list = new ArrayList<>(); List<BlockDisplay> list = new ArrayList<>();
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
Location initialLoc = player.getLocation().add(0, 1, 0); Location initialLoc = player.getLocation().add(0, 1, 0);
@@ -132,13 +134,9 @@ public class NetheriteAnimation extends MaterialAnimation {
@Override @Override
public void onRemove(OfflinePlayer player) { public void onRemove(OfflinePlayer player) {
List<BlockDisplay> displays = activeDisplays.remove(player.getUniqueId()); List<BlockDisplay> displays = activeDisplays.get(player.getUniqueId());
if (displays != null) { if (displays == null || displays.isEmpty()) return;
for (BlockDisplay display : displays) { displays.forEach(BlockDisplay::remove);
if (!display.isDead()) { activeDisplays.remove(player.getUniqueId());
display.remove();
}
}
}
} }
} }