Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ee0d93385d |
@@ -868,6 +868,8 @@ public final class Canalhandia extends JavaPlugin implements Listener {
|
|||||||
int x = safeLoc.getBlockX();
|
int x = safeLoc.getBlockX();
|
||||||
int y = safeLoc.getBlockY();
|
int y = safeLoc.getBlockY();
|
||||||
int z = safeLoc.getBlockZ();
|
int z = safeLoc.getBlockZ();
|
||||||
|
pendingDeathCoords.put(player.getUniqueId(), new DeathCoords(
|
||||||
|
x + " " + y + " " + z + " (" + safeLoc.getWorld().getName() + " - Baú do Vácuo)", false));
|
||||||
getServer().getScheduler().runTaskLater(this, () -> {
|
getServer().getScheduler().runTaskLater(this, () -> {
|
||||||
if (player.isOnline()) {
|
if (player.isOnline()) {
|
||||||
player.sendMessage(Component.text("[Canalhandia] ", NamedTextColor.GOLD)
|
player.sendMessage(Component.text("[Canalhandia] ", NamedTextColor.GOLD)
|
||||||
@@ -884,6 +886,9 @@ public final class Canalhandia extends JavaPlugin implements Listener {
|
|||||||
event.setKeepLevel(true);
|
event.setKeepLevel(true);
|
||||||
event.setDroppedExp(0);
|
event.setDroppedExp(0);
|
||||||
}
|
}
|
||||||
|
pendingDeathCoords.put(player.getUniqueId(), new DeathCoords(
|
||||||
|
player.getLocation().getBlockX() + " " + player.getLocation().getBlockY() + " " + player.getLocation().getBlockZ()
|
||||||
|
+ " (" + player.getWorld().getName() + ")", true));
|
||||||
getServer().getScheduler().runTaskLater(this, () -> {
|
getServer().getScheduler().runTaskLater(this, () -> {
|
||||||
if (player.isOnline()) {
|
if (player.isOnline()) {
|
||||||
player.sendMessage(Component.text("[Canalhandia] ", NamedTextColor.GOLD)
|
player.sendMessage(Component.text("[Canalhandia] ", NamedTextColor.GOLD)
|
||||||
@@ -905,7 +910,7 @@ public final class Canalhandia extends JavaPlugin implements Listener {
|
|||||||
* {@code [F]} mourning row and never touches {@code deathMessage}, so both
|
* {@code [F]} mourning row and never touches {@code deathMessage}, so both
|
||||||
* fire on the same event without conflict.
|
* fire on the same event without conflict.
|
||||||
*/
|
*/
|
||||||
@EventHandler
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
public void onDeathComic(PlayerDeathEvent event) {
|
public void onDeathComic(PlayerDeathEvent event) {
|
||||||
if (!settings.moduleEnabled(Module.MORTES)) {
|
if (!settings.moduleEnabled(Module.MORTES)) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1999,7 +1999,7 @@ final class CanalhandiaCommand implements CommandExecutor, TabCompleter {
|
|||||||
try {
|
try {
|
||||||
double hours = Double.parseDouble(args[1]);
|
double hours = Double.parseDouble(args[1]);
|
||||||
if (hours <= 0 && isAdmin) {
|
if (hours <= 0 && isAdmin) {
|
||||||
plugin.chunkLoaders().addTime(loader.id(), -loader.expiresAt()); // permanent
|
plugin.chunkLoaders().setExpiresAt(loader.id(), 0L); // permanent
|
||||||
Msg.ok(sender, "Âncora " + loader.displayName() + " definida como PERMANENTE.");
|
Msg.ok(sender, "Âncora " + loader.displayName() + " definida como PERMANENTE.");
|
||||||
} else {
|
} else {
|
||||||
long millis = (long) (hours * 3600_000L);
|
long millis = (long) (hours * 3600_000L);
|
||||||
@@ -2202,7 +2202,7 @@ final class CanalhandiaCommand implements CommandExecutor, TabCompleter {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
int newLimit = Math.max(0, Integer.parseInt(args[1]));
|
int newLimit = Math.max(0, Integer.parseInt(args[1]));
|
||||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + target.getName() + " permission set canalhandia.chunkloader.limite." + newLimit);
|
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + target.getUniqueId() + " permission set canalhandia.chunkloader.limite." + newLimit);
|
||||||
Msg.ok(sender, "Limite de " + target.getName() + " definido para " + newLimit + " âncoras.");
|
Msg.ok(sender, "Limite de " + target.getName() + " definido para " + newLimit + " âncoras.");
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
Msg.error(sender, "Quantidade inválida: " + args[1]);
|
Msg.error(sender, "Quantidade inválida: " + args[1]);
|
||||||
|
|||||||
@@ -300,13 +300,17 @@ final class ChunkLoaderListener implements Listener {
|
|||||||
if (!plugin.settings().moduleEnabled(Module.CHUNKLOADER)) {
|
if (!plugin.settings().moduleEnabled(Module.CHUNKLOADER)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
CreatureSpawnEvent.SpawnReason reason = event.getSpawnReason();
|
||||||
|
if (reason != CreatureSpawnEvent.SpawnReason.SPAWNER && reason != CreatureSpawnEvent.SpawnReason.CUSTOM) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Location loc = event.getLocation();
|
Location loc = event.getLocation();
|
||||||
World w = loc.getWorld();
|
World w = loc.getWorld();
|
||||||
if (w == null) {
|
if (w == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ChunkLoader loader = plugin.chunkLoaders().byChunk(w.getName(), loc.getBlockX() >> 4, loc.getBlockZ() >> 4);
|
ChunkLoader loader = plugin.chunkLoaders().byChunk(w.getName(), loc.getBlockX() >> 4, loc.getBlockZ() >> 4);
|
||||||
if (loader != null && event.getEntity() instanceof Mob mob) {
|
if (loader != null && loader.enabled() && event.getEntity() instanceof Mob mob) {
|
||||||
mob.setRemoveWhenFarAway(false);
|
mob.setRemoveWhenFarAway(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,6 +144,29 @@ final class ChunkLoaders {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a specific expiration timestamp (or 0 for permanent) for a chunk loader.
|
||||||
|
*/
|
||||||
|
boolean setExpiresAt(long id, long expiresAt) {
|
||||||
|
ChunkLoader updated = null;
|
||||||
|
synchronized (loaders) {
|
||||||
|
for (int i = 0; i < loaders.size(); i++) {
|
||||||
|
ChunkLoader curr = loaders.get(i);
|
||||||
|
if (curr.id() == id) {
|
||||||
|
updated = curr.withExpiresAt(expiresAt).withEnabled(true);
|
||||||
|
loaders.set(i, updated);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (updated != null) {
|
||||||
|
addTicket(updated);
|
||||||
|
save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renames an existing chunk loader.
|
* Renames an existing chunk loader.
|
||||||
*/
|
*/
|
||||||
@@ -447,15 +470,21 @@ final class ChunkLoaders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static EntityType pickEntityType(World w, Block space, int light) {
|
static EntityType pickEntityType(World w, Block space, int light) {
|
||||||
World.Environment env = w.getEnvironment();
|
boolean isSlime = false;
|
||||||
ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
try {
|
||||||
|
isSlime = space.getChunk().isSlimeChunk();
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
return pickEntityType(w.getEnvironment(), isSlime, space.getY(), light, ThreadLocalRandom.current().nextInt(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
static EntityType pickEntityType(World.Environment env, boolean isSlimeChunk, int y, int light, int roll) {
|
||||||
if (env == World.Environment.NETHER) {
|
if (env == World.Environment.NETHER) {
|
||||||
if (light > 11) return null;
|
if (light > 11) return null;
|
||||||
int roll = rnd.nextInt(100);
|
int r = Math.floorMod(roll, 100);
|
||||||
if (roll < 45) return EntityType.ZOMBIFIED_PIGLIN;
|
if (r < 45) return EntityType.ZOMBIFIED_PIGLIN;
|
||||||
if (roll < 65) return EntityType.WITHER_SKELETON;
|
if (r < 65) return EntityType.WITHER_SKELETON;
|
||||||
if (roll < 85) return EntityType.BLAZE;
|
if (r < 85) return EntityType.BLAZE;
|
||||||
return EntityType.MAGMA_CUBE;
|
return EntityType.MAGMA_CUBE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,8 +492,7 @@ final class ChunkLoaders {
|
|||||||
return EntityType.ENDERMAN;
|
return EntityType.ENDERMAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isSlimeChunk = space.getChunk().isSlimeChunk() && space.getY() < 40;
|
if (isSlimeChunk && y < 40 && light <= 7 && roll % 3 == 0) {
|
||||||
if (isSlimeChunk && light <= 7 && rnd.nextInt(3) == 0) {
|
|
||||||
return EntityType.SLIME;
|
return EntityType.SLIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,11 +500,11 @@ final class ChunkLoaders {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int roll = rnd.nextInt(100);
|
int r = Math.floorMod(roll, 100);
|
||||||
if (roll < 35) return EntityType.ZOMBIE;
|
if (r < 35) return EntityType.ZOMBIE;
|
||||||
if (roll < 65) return EntityType.SKELETON;
|
if (r < 65) return EntityType.SKELETON;
|
||||||
if (roll < 85) return EntityType.CREEPER;
|
if (r < 85) return EntityType.CREEPER;
|
||||||
if (roll < 95) return EntityType.SPIDER;
|
if (r < 95) return EntityType.SPIDER;
|
||||||
return EntityType.WITCH;
|
return EntityType.WITCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,24 +108,35 @@ public final class VoidProtection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean isSafeGround(Block block) {
|
static boolean isSafeGround(Block block) {
|
||||||
if (block == null) {
|
return block != null && isSafeGroundMaterial(block.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSafeGroundMaterial(Material mat) {
|
||||||
|
if (mat == null || mat == Material.AIR || mat == Material.CAVE_AIR || mat == Material.VOID_AIR) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Material mat = block.getType();
|
if (mat == Material.LAVA || mat == Material.WATER || mat == Material.FIRE || mat == Material.SOUL_FIRE
|
||||||
if (mat.isAir() || !mat.isSolid()) {
|
|| mat == Material.CACTUS || mat == Material.MAGMA_BLOCK || mat == Material.SWEET_BERRY_BUSH
|
||||||
|
|| mat == Material.WITHER_ROSE || mat == Material.POWDER_SNOW) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return mat != Material.LAVA && mat != Material.FIRE && mat != Material.SOUL_FIRE
|
try {
|
||||||
&& mat != Material.CACTUS && mat != Material.MAGMA_BLOCK && mat != Material.SWEET_BERRY_BUSH
|
return mat.isSolid();
|
||||||
&& mat != Material.WITHER_ROSE && mat != Material.POWDER_SNOW;
|
} catch (Exception | LinkageError e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isReplaceable(Block block) {
|
static boolean isReplaceable(Block block) {
|
||||||
if (block == null) {
|
return block != null && isReplaceableMaterial(block.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isReplaceableMaterial(Material mat) {
|
||||||
|
if (mat == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Material mat = block.getType();
|
return mat == Material.AIR || mat == Material.CAVE_AIR || mat == Material.VOID_AIR
|
||||||
return mat.isAir() || mat == Material.SHORT_GRASS || mat == Material.TALL_GRASS
|
|| mat == Material.SHORT_GRASS || mat == Material.TALL_GRASS
|
||||||
|| mat == Material.SNOW || mat == Material.FERN || mat == Material.LARGE_FERN;
|
|| mat == Material.SNOW || mat == Material.FERN || mat == Material.LARGE_FERN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -151,6 +151,50 @@ class ChunkLoaderTest {
|
|||||||
ChunkLoader expired = timed.withExpiresAt(System.currentTimeMillis() - 1000L);
|
ChunkLoader expired = timed.withExpiresAt(System.currentTimeMillis() - 1000L);
|
||||||
assertTrue(expired.isExpired());
|
assertTrue(expired.isExpired());
|
||||||
assertEquals("Expirado", expired.timeLeft());
|
assertEquals("Expirado", expired.timeLeft());
|
||||||
|
|
||||||
|
assertTrue(loaders.setExpiresAt(loader.id(), 0L));
|
||||||
|
ChunkLoader permanent = loaders.byId(loader.id());
|
||||||
|
assertNotNull(permanent);
|
||||||
|
assertEquals(0L, permanent.expiresAt());
|
||||||
|
assertEquals("Permanente", permanent.timeLeft());
|
||||||
|
assertFalse(permanent.isExpired());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void pickEntityTypeReturnsExpectedEntitiesByEnvironment() {
|
||||||
|
// Nether
|
||||||
|
assertEquals(org.bukkit.entity.EntityType.ZOMBIFIED_PIGLIN,
|
||||||
|
ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NETHER, false, 64, 0, 10));
|
||||||
|
assertEquals(org.bukkit.entity.EntityType.WITHER_SKELETON,
|
||||||
|
ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NETHER, false, 64, 0, 50));
|
||||||
|
assertEquals(org.bukkit.entity.EntityType.BLAZE,
|
||||||
|
ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NETHER, false, 64, 0, 75));
|
||||||
|
assertEquals(org.bukkit.entity.EntityType.MAGMA_CUBE,
|
||||||
|
ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NETHER, false, 64, 0, 90));
|
||||||
|
assertNull(ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NETHER, false, 64, 12, 10));
|
||||||
|
|
||||||
|
// End
|
||||||
|
assertEquals(org.bukkit.entity.EntityType.ENDERMAN,
|
||||||
|
ChunkLoaders.pickEntityType(org.bukkit.World.Environment.THE_END, false, 64, 15, 50));
|
||||||
|
|
||||||
|
// Overworld Slime Chunk
|
||||||
|
assertEquals(org.bukkit.entity.EntityType.SLIME,
|
||||||
|
ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NORMAL, true, 30, 5, 0));
|
||||||
|
|
||||||
|
// Overworld Normal Darkness
|
||||||
|
assertEquals(org.bukkit.entity.EntityType.ZOMBIE,
|
||||||
|
ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NORMAL, false, 64, 0, 10));
|
||||||
|
assertEquals(org.bukkit.entity.EntityType.SKELETON,
|
||||||
|
ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NORMAL, false, 64, 0, 45));
|
||||||
|
assertEquals(org.bukkit.entity.EntityType.CREEPER,
|
||||||
|
ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NORMAL, false, 64, 0, 75));
|
||||||
|
assertEquals(org.bukkit.entity.EntityType.SPIDER,
|
||||||
|
ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NORMAL, false, 64, 0, 90));
|
||||||
|
assertEquals(org.bukkit.entity.EntityType.WITCH,
|
||||||
|
ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NORMAL, false, 64, 0, 99));
|
||||||
|
|
||||||
|
// Overworld in Light -> Null
|
||||||
|
assertNull(ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NORMAL, false, 64, 5, 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -32,6 +32,42 @@ class VoidProtectionTest {
|
|||||||
assertFalse(VoidProtection.rescueToChest(List.of(), null));
|
assertFalse(VoidProtection.rescueToChest(List.of(), null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void validatesSafeGroundMaterials() {
|
||||||
|
assertTrue(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.STONE));
|
||||||
|
assertTrue(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.GRASS_BLOCK));
|
||||||
|
assertTrue(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.DIRT));
|
||||||
|
assertTrue(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.OBSIDIAN));
|
||||||
|
|
||||||
|
assertFalse(VoidProtection.isSafeGroundMaterial(null));
|
||||||
|
assertFalse(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.AIR));
|
||||||
|
assertFalse(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.LAVA));
|
||||||
|
assertFalse(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.FIRE));
|
||||||
|
assertFalse(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.SOUL_FIRE));
|
||||||
|
assertFalse(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.CACTUS));
|
||||||
|
assertFalse(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.MAGMA_BLOCK));
|
||||||
|
assertFalse(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.SWEET_BERRY_BUSH));
|
||||||
|
assertFalse(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.WITHER_ROSE));
|
||||||
|
assertFalse(VoidProtection.isSafeGroundMaterial(org.bukkit.Material.POWDER_SNOW));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void validatesReplaceableMaterials() {
|
||||||
|
assertTrue(VoidProtection.isReplaceableMaterial(org.bukkit.Material.AIR));
|
||||||
|
assertTrue(VoidProtection.isReplaceableMaterial(org.bukkit.Material.CAVE_AIR));
|
||||||
|
assertTrue(VoidProtection.isReplaceableMaterial(org.bukkit.Material.VOID_AIR));
|
||||||
|
assertTrue(VoidProtection.isReplaceableMaterial(org.bukkit.Material.SHORT_GRASS));
|
||||||
|
assertTrue(VoidProtection.isReplaceableMaterial(org.bukkit.Material.TALL_GRASS));
|
||||||
|
assertTrue(VoidProtection.isReplaceableMaterial(org.bukkit.Material.SNOW));
|
||||||
|
assertTrue(VoidProtection.isReplaceableMaterial(org.bukkit.Material.FERN));
|
||||||
|
assertTrue(VoidProtection.isReplaceableMaterial(org.bukkit.Material.LARGE_FERN));
|
||||||
|
|
||||||
|
assertFalse(VoidProtection.isReplaceableMaterial(null));
|
||||||
|
assertFalse(VoidProtection.isReplaceableMaterial(org.bukkit.Material.STONE));
|
||||||
|
assertFalse(VoidProtection.isReplaceableMaterial(org.bukkit.Material.CHEST));
|
||||||
|
assertFalse(VoidProtection.isReplaceableMaterial(org.bukkit.Material.OBSIDIAN));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void nullBlocksAreNeitherSafeNorReplaceable() {
|
void nullBlocksAreNeitherSafeNorReplaceable() {
|
||||||
assertFalse(VoidProtection.isSafeGround(null));
|
assertFalse(VoidProtection.isSafeGround(null));
|
||||||
|
|||||||
Reference in New Issue
Block a user