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 QuartzAnimation());
trimManager.register(new RedstoneAnimation());
trimManager.register();
trimManager.startTicking();
}

View File

@@ -74,16 +74,12 @@ public class AdminCommand implements QuickCommand, Data {
)
)
).then(
b.arg("update")
).then(
b.arg("reload")
).then(
b.arg("cleanup")
b.arg("update","reload","cleanup")
);
}
private void handleUpdate(CommandSender sender, Args args) {
infoAny(sender,"Checking for an updated...");
infoAny(sender,"Checking for an update...");
Bukkit.getScheduler().runTask(main.getPlugin(),()->{
if (AutoUpdater.checkUpdate(main.getPlugin(),main.getCommon())) {
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.");
});
}

View File

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

View File

@@ -48,6 +48,9 @@ public class Freeze {
private final Location backLocation;
private final Consumer<OfflinePlayer> onQuit;
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) {
this.uuid = uuid;
@@ -73,5 +76,29 @@ public class Freeze {
if (player == null) return;
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.world.Snapshot;
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.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.BoundingBox;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
public class JailHeadWand extends AbstractWand implements QuickListener {
public JailHeadWand() {
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());
}
private final Map<UUID,Jail> jailed = new HashMap<>();
@Override
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 final UUID prisoner;
private final List<Snapshot> changedBlocks = new ArrayList<>();
private final Map<Block, Snapshot> snapshots = new HashMap<>();
public Jail(Player prisoner) {
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 y = loc.getBlockY();
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 dz = z - 1; dz < z + 1; dz++) {
Location pointer = loc.clone();
pointer.setX(dx);
pointer.setY(dy);
pointer.setZ(dz);
for (int dx = -1; dx <= 1; dx++) {
for (int dy = 0; dy <= 3; dy++) {
for (int dz = -1; dz <= 1; dz++) {
int bx = x + dx;
int by = y + dy;
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;
import me.trouper.alias.server.Main;
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.utils.ArmorUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
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.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@Registrar(exclude = true)
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) {
animations.put(animation.getMaterial(), 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);
allAnimations.add(animation);
}
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) {
ItemStack[] armor = player.getInventory().getArmorContents();
if (armor.length != 4) return null;
public void tickPlayer(Player player, int globalTime) {
UUID playerId = player.getUniqueId();
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;
for (ItemStack piece : armor) {
if (!ArmorUtils.isArmor(piece)) return null;
if (activeAnimation == null) {
return;
} 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();
if (!(meta instanceof ArmorMeta armorMeta)) return null;
if (!armorMeta.hasTrim()) return null;
MovementTracker tracker = trackerMap.computeIfAbsent(playerId,k -> new MovementTracker(player.getLocation()));
long loopTime = globalTime % activeAnimation.getLoopDuration();
ArmorTrim trim = armorMeta.getTrim();
if (trim == null) return null;
if (tracker.isStationary) {
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());
if (vm == null) return null;
tracker.tick(player.getLocation());
}
if (found == null) {
found = vm;
} else if (found != vm) {
public static class MovementTracker {
private Location lastLocation;
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 found;
}
private boolean shouldHide(Player player) {
return getStorage().disabledOwnParticles.contains(player.getUniqueId().toString());
}
private Set<Player> getViewers(Player player) {
if (shouldHide(player)) return new HashSet<>();
return Bukkit.getOnlinePlayers().stream().filter(viewer-> !getStorage().disabledGlobalParticles.contains(viewer.getUniqueId().toString())).collect(Collectors.toSet());
if (shouldHide(player)) {
return Collections.emptySet();
}
private static class ActiveTrim {
final ValidMaterial material;
long ticks;
long lastMoveTimestamp;
Location lastCheckedLocation;
ActiveTrim(ValidMaterial material, Location initialLocation) {
this.material = material;
this.ticks = 0;
this.lastMoveTimestamp = System.currentTimeMillis();
this.lastCheckedLocation = initialLocation;
}
return Bukkit.getOnlinePlayers().stream()
.filter(viewer -> !getStorage().disabledGlobalParticles.contains(viewer.getUniqueId().toString()))
.collect(Collectors.toSet());
}
@EventHandler
public void onLeave(PlayerQuitEvent e) {
safeRemove(e.getPlayer());
public void onQuit(PlayerQuitEvent e) {
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;
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;
public enum ValidMaterial {
@@ -36,4 +42,34 @@ public enum ValidMaterial {
name = name.toUpperCase();
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;
import me.trouper.alias.server.systems.Verbose;
import me.trouper.alias.server.systems.visual.DisplayUtils;
import me.trouper.alias.server.systems.visual.ParticleUtils;
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;
List<BlockDisplay> displays = activeDisplays.computeIfAbsent(playerId, id -> {
Verbose.send("{0} needed new BlockDisplays",player.getName());
List<BlockDisplay> list = new ArrayList<>();
for (int i = 0; i < 4; i++) {
Location initialLoc = player.getLocation().add(0, 1, 0);
@@ -132,13 +134,9 @@ public class NetheriteAnimation extends MaterialAnimation {
@Override
public void onRemove(OfflinePlayer player) {
List<BlockDisplay> displays = activeDisplays.remove(player.getUniqueId());
if (displays != null) {
for (BlockDisplay display : displays) {
if (!display.isDead()) {
display.remove();
}
}
}
List<BlockDisplay> displays = activeDisplays.get(player.getUniqueId());
if (displays == null || displays.isEmpty()) return;
displays.forEach(BlockDisplay::remove);
activeDisplays.remove(player.getUniqueId());
}
}