feat(chunkloader): add comprehensive configuration for simulation, passive entities, mob cap, and fuel
This commit is contained in:
@@ -36,7 +36,7 @@ final class ChunkLoaders {
|
||||
|
||||
private static final String PERM_LIMIT_PREFIX = "canalhandia.chunkloader.limite.";
|
||||
|
||||
private final Plugin plugin;
|
||||
private final Canalhandia plugin;
|
||||
private final File file;
|
||||
private final List<ChunkLoader> loaders = new ArrayList<>();
|
||||
private final AtomicLong nextId = new AtomicLong(1);
|
||||
@@ -48,7 +48,7 @@ final class ChunkLoaders {
|
||||
return t;
|
||||
});
|
||||
|
||||
ChunkLoaders(Plugin plugin, File file) {
|
||||
ChunkLoaders(Canalhandia plugin, File file) {
|
||||
this.plugin = plugin;
|
||||
this.file = file;
|
||||
load();
|
||||
@@ -97,11 +97,21 @@ final class ChunkLoaders {
|
||||
* Registers a new chunk loader and activates the ticket in the world.
|
||||
*/
|
||||
ChunkLoader add(String ownerUuid, String ownerName, String world, int x, int y, int z) {
|
||||
return add(ownerUuid, ownerName, world, x, y, z, "", 0L);
|
||||
return add(ownerUuid, ownerName, world, x, y, z, "", defaultInitialExpiration());
|
||||
}
|
||||
|
||||
ChunkLoader add(String ownerUuid, String ownerName, String world, int x, int y, int z, String name) {
|
||||
return add(ownerUuid, ownerName, world, x, y, z, name, 0L);
|
||||
return add(ownerUuid, ownerName, world, x, y, z, name, defaultInitialExpiration());
|
||||
}
|
||||
|
||||
private long defaultInitialExpiration() {
|
||||
if (plugin != null && plugin.settings() != null && plugin.settings().chunkLoaderRequiresTime()) {
|
||||
double hours = plugin.settings().chunkLoaderInitialHours();
|
||||
if (hours > 0) {
|
||||
return System.currentTimeMillis() + (long) (hours * 3600_000L);
|
||||
}
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
ChunkLoader add(String ownerUuid, String ownerName, String world, int x, int y, int z, String name, long expiresAt) {
|
||||
@@ -417,28 +427,34 @@ final class ChunkLoaders {
|
||||
}
|
||||
Chunk chunk = w.getChunkAt(loader.chunkX(), loader.chunkZ());
|
||||
|
||||
// 1. Keep mob spawners (dungeon / blaze / skeleton cages) active
|
||||
for (BlockState state : chunk.getTileEntities()) {
|
||||
if (state instanceof CreatureSpawner spawner) {
|
||||
if (spawner.getRequiredPlayerRange() < 1024) {
|
||||
spawner.setRequiredPlayerRange(2048);
|
||||
spawner.update(true, false);
|
||||
boolean spawnersActive = plugin.settings() == null || plugin.settings().chunkLoaderSpawnersActive();
|
||||
boolean monsterSpawning = plugin.settings() == null || plugin.settings().chunkLoaderMonsterSpawning();
|
||||
int monsterCap = plugin.settings() != null ? plugin.settings().chunkLoaderMonsterCap() : 20;
|
||||
|
||||
// 1. Keep mob spawners (dungeon / blaze / skeleton cages) active if enabled
|
||||
if (spawnersActive) {
|
||||
for (BlockState state : chunk.getTileEntities()) {
|
||||
if (state instanceof CreatureSpawner spawner) {
|
||||
if (spawner.getRequiredPlayerRange() < 1024) {
|
||||
spawner.setRequiredPlayerRange(2048);
|
||||
spawner.update(true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Simulate natural mob spawning (dark platforms / slime / nether farms)
|
||||
long mobCount = 0;
|
||||
for (Entity entity : chunk.getEntities()) {
|
||||
if (entity instanceof Mob) {
|
||||
mobCount++;
|
||||
// 2. Simulate natural mob spawning (dark platforms / slime / nether farms) if enabled
|
||||
if (monsterSpawning) {
|
||||
long mobCount = 0;
|
||||
for (Entity entity : chunk.getEntities()) {
|
||||
if (entity instanceof Mob) {
|
||||
mobCount++;
|
||||
}
|
||||
}
|
||||
if (mobCount < monsterCap) {
|
||||
simulateNaturalSpawning(w, loader, chunk);
|
||||
}
|
||||
}
|
||||
if (mobCount >= 20) {
|
||||
continue; // Respect chunk mob cap
|
||||
}
|
||||
|
||||
simulateNaturalSpawning(w, loader, chunk);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,6 +597,54 @@ final class Settings {
|
||||
set("chunkloader.bluemap", enabled);
|
||||
}
|
||||
|
||||
boolean chunkLoaderSpawnersActive() {
|
||||
return plugin.getConfig().getBoolean("chunkloader.simulacao.gaiolas-ativas", true);
|
||||
}
|
||||
|
||||
void chunkLoaderSpawnersActive(boolean active) {
|
||||
set("chunkloader.simulacao.gaiolas-ativas", active);
|
||||
}
|
||||
|
||||
boolean chunkLoaderMonsterSpawning() {
|
||||
return plugin.getConfig().getBoolean("chunkloader.simulacao.spawn-monstros", true);
|
||||
}
|
||||
|
||||
void chunkLoaderMonsterSpawning(boolean spawning) {
|
||||
set("chunkloader.simulacao.spawn-monstros", spawning);
|
||||
}
|
||||
|
||||
int chunkLoaderMonsterCap() {
|
||||
return Math.max(1, plugin.getConfig().getInt("chunkloader.simulacao.limite-monstros-chunk", 20));
|
||||
}
|
||||
|
||||
void chunkLoaderMonsterCap(int cap) {
|
||||
set("chunkloader.simulacao.limite-monstros-chunk", Math.max(1, cap));
|
||||
}
|
||||
|
||||
boolean chunkLoaderPassiveEntities() {
|
||||
return plugin.getConfig().getBoolean("chunkloader.simulacao.tick-entidades-passivas", true);
|
||||
}
|
||||
|
||||
void chunkLoaderPassiveEntities(boolean active) {
|
||||
set("chunkloader.simulacao.tick-entidades-passivas", active);
|
||||
}
|
||||
|
||||
boolean chunkLoaderRequiresTime() {
|
||||
return plugin.getConfig().getBoolean("chunkloader.combustivel.requer-tempo", true);
|
||||
}
|
||||
|
||||
void chunkLoaderRequiresTime(boolean required) {
|
||||
set("chunkloader.combustivel.requer-tempo", required);
|
||||
}
|
||||
|
||||
double chunkLoaderInitialHours() {
|
||||
return Math.max(0.0, plugin.getConfig().getDouble("chunkloader.combustivel.tempo-inicial-horas", 24.0));
|
||||
}
|
||||
|
||||
void chunkLoaderInitialHours(double hours) {
|
||||
set("chunkloader.combustivel.tempo-inicial-horas", Math.max(0.0, hours));
|
||||
}
|
||||
|
||||
// --- salvavoid ----------------------------------------------------------
|
||||
|
||||
int voidProtectionRadius() {
|
||||
|
||||
@@ -344,3 +344,43 @@ mortes:
|
||||
- "BONE | Osso da Sorte | Um ossinho pra você, campeão."
|
||||
- "COOKIE | Cookie de Consolação | Cookie de consolação. Vai que melhora."
|
||||
- "ROTTEN_FLESH | Carne Podre | É o que tinha sobrado na despensa."
|
||||
|
||||
# --- Âncoras de Chunk (Chunk Loaders) ----------------------------------------
|
||||
chunkloader:
|
||||
# Limite máximo de âncoras ativas por jogador por padrão.
|
||||
# Pode ser alterado por jogador com /chunkloader limite <jogador> <qtd>.
|
||||
limite-padrao: 1
|
||||
|
||||
# Exibe os marcadores de âncoras ativas no BlueMap.
|
||||
bluemap: true
|
||||
|
||||
# Configurações de simulação de entidades na chunk carregada:
|
||||
simulacao:
|
||||
# Se true, mantém ativas gaiolas de monstros (spawners de blaze, esqueletos, etc.)
|
||||
# mesmo sem jogadores por perto.
|
||||
gaiolas-ativas: true
|
||||
|
||||
# Se true, simula o surgimento natural de monstros em plataformas escuras,
|
||||
# slime chunks e fortalezas do nether. Se false, apenas entidades existentes funcionam.
|
||||
spawn-monstros: true
|
||||
|
||||
# Teto máximo de monstros na chunk antes de pausar o spawn natural (evita acúmulo de lag).
|
||||
limite-monstros-chunk: 20
|
||||
|
||||
# Se true, mantém animais, aldeões, ferro-golems e colheitas sendo processados na chunk.
|
||||
tick-entidades-passivas: true
|
||||
|
||||
# Sistema de combustível e tempo de expiração:
|
||||
combustivel:
|
||||
# Se true, âncoras requerem abastecimento com itens e têm tempo de expiração.
|
||||
# Se false, todas as âncoras colocadas são permanentes por padrão.
|
||||
requer-tempo: true
|
||||
|
||||
# Tempo inicial padrão dado ao criar e colocar uma nova âncora (em horas).
|
||||
tempo-inicial-horas: 24
|
||||
|
||||
# --- Salva-Void (Resgate de Morte no Vazio) -----------------------------------
|
||||
salvavoid:
|
||||
# Raio máximo de busca em blocos a partir de onde o jogador caiu para achar
|
||||
# terreno seguro e colocar o baú com os itens resgatados.
|
||||
raio-busca: 32
|
||||
|
||||
@@ -203,6 +203,15 @@ class ChunkLoaderTest {
|
||||
assertNull(ChunkLoaders.pickEntityType(org.bukkit.World.Environment.NORMAL, false, 64, 5, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
void createsLoaderWithInitialExpiration() {
|
||||
long targetExpiry = System.currentTimeMillis() + 86400_000L;
|
||||
ChunkLoader loader = loaders.add("uuid-1", "Marcos", "world", 100, 64, 200, "Base", targetExpiry);
|
||||
assertEquals(targetExpiry, loader.expiresAt());
|
||||
assertFalse(loader.isExpired());
|
||||
assertTrue(loader.timeLeft().contains("h"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void simulationSafelyNoopsWithNullPlugin() {
|
||||
loaders.startSimulation();
|
||||
|
||||
Reference in New Issue
Block a user