feat: add fine-grained biome control to Minestom world builder

Introduced a `doFineGrainedBiomes` flag to allow fine-grained biome control per chunk. This helps mitigate client disconnection issues caused by a Minestom biome encoding bug, with a plan to deprecate once the bug is resolved. Adjusted relevant classes and the example implementation to support this feature.
This commit is contained in:
Christian Bergschneider 2025-06-04 21:25:35 +02:00
parent d9a4d64b17
commit b12fe77f32
No known key found for this signature in database
GPG Key ID: 3991F97F5FA28D3E
5 changed files with 49 additions and 10 deletions

View File

@ -6,6 +6,7 @@ import net.minestom.server.command.builder.Command;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode;
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
import net.minestom.server.event.player.PlayerDisconnectEvent;
import net.minestom.server.event.player.PlayerSpawnEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.LightingChunk;
@ -23,6 +24,7 @@ public class TerraMinestomExample {
private final MinecraftServer server = MinecraftServer.init();
private Instance instance;
private TerraMinestomWorld world;
private final TerraMinestomPlatform platform = new TerraMinestomPlatform();
public void createNewInstance() {
instance = MinecraftServer.getInstanceManager().createInstanceContainer();
@ -30,9 +32,9 @@ public class TerraMinestomExample {
}
public void attachTerra() {
TerraMinestomPlatform platform = new TerraMinestomPlatform();
world = platform.worldBuilder(instance)
.defaultPack()
.doFineGrainedBiomes(false)
.attach();
}
@ -122,6 +124,7 @@ public class TerraMinestomExample {
private void regenerate() {
instance.sendMessage(Component.text("Regenerating world"));
Instance oldInstance = instance;
platform.reload();
createNewInstance();
attachTerra();
preloadWorldAndMeasure();

View File

@ -24,6 +24,7 @@ public class TerraMinestomWorldBuilder {
private EntityFactory entityFactory = new DefaultEntityFactory();
private BlockEntityFactory blockEntityFactory = new DefaultBlockEntityFactory();
private BiomeFactory biomeFactory = new MinestomUserDefinedBiomeFactory();
private boolean doFineGrainedBiomes = true;
public TerraMinestomWorldBuilder(TerraMinestomPlatform platform, Instance instance) {
this.platform = platform;
@ -70,7 +71,20 @@ public class TerraMinestomWorldBuilder {
return this;
}
/**
* Due to a current bug with the minestom biome encoder, sometimes, the client gets kicked when decoding a chunk
* packet with more than one biome. Until this is fixed in minestom, one can disable fine-grained biomes to prevent
* this issue.
*
* @deprecated Scheduled for removal once Minestom rolls out a fix
*/
@Deprecated
public TerraMinestomWorldBuilder doFineGrainedBiomes(boolean doFineGrainedBiomes) {
this.doFineGrainedBiomes = doFineGrainedBiomes;
return this;
}
public TerraMinestomWorld attach() {
return new TerraMinestomWorld(platform, instance, pack, seed, entityFactory, blockEntityFactory, biomeFactory);
return new TerraMinestomWorld(platform, instance, pack, seed, entityFactory, blockEntityFactory, biomeFactory, doFineGrainedBiomes);
}
}

View File

@ -2,16 +2,17 @@ package com.dfsek.terra.minestom.biome;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.minestom.api.BiomeFactory;
import java.util.HashMap;
public class MinestomUserDefinedBiomePool {
private final HashMap<String, UserDefinedBiome> biomes = new HashMap<>();
private final MinestomUserDefinedBiomeFactory factory;
private final BiomeFactory factory;
private final ConfigPack configPack;
public MinestomUserDefinedBiomePool(ConfigPack configPack, MinestomUserDefinedBiomeFactory factory) {
public MinestomUserDefinedBiomePool(ConfigPack configPack, BiomeFactory factory) {
this.configPack = configPack;
this.factory = factory;
}

View File

@ -26,6 +26,7 @@ public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrappe
private ChunkGenerator generator;
private final TerraMinestomWorld world;
private final BiomeProvider biomeProvider;
private final boolean doFineGrainedBiomes;
private ConfigPack pack;
private final MinestomUserDefinedBiomePool biomePool;
@ -34,13 +35,15 @@ public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrappe
ChunkGenerator generator,
TerraMinestomWorld world,
ConfigPack pack,
MinestomUserDefinedBiomePool biomePool
MinestomUserDefinedBiomePool biomePool,
boolean doFineGrainedBiomes
) {
this.generator = generator;
this.world = world;
this.pack = pack;
this.biomePool = biomePool;
biomeProvider = pack.getBiomeProvider().caching(platform);
this.biomeProvider = pack.getBiomeProvider();
this.doFineGrainedBiomes = doFineGrainedBiomes;
this.cache = new GeneratedChunkCache(world.getDimensionType(), generator, world, biomeProvider);
preloadBiomes();
}
@ -56,12 +59,28 @@ public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrappe
int z = start.chunkZ();
int blockX = start.blockX();
int blockZ = start.blockZ();
int minY = world.getMinHeight();
int maxY = world.getMaxHeight();
CachedChunk chunk = cache.at(x, z);
UnitModifier modifier = unit.modifier();
chunk.writeRelative(modifier);
UserDefinedBiome userDefinedBiome = biomePool.getBiome(biomeProvider.getBiome(blockX, 100, blockZ, world.getSeed()));
modifier.fillBiome(userDefinedBiome.registry());
if(doFineGrainedBiomes) {
for(int y = minY; y < maxY; y++) {
for(int absoluteX = blockX; absoluteX < blockX + 16; absoluteX++) {
for(int absoluteZ = blockZ; absoluteZ < blockZ + 16; absoluteZ++) {
UserDefinedBiome userDefinedBiome = biomePool.getBiome(
biomeProvider.getBiome(absoluteX, y, absoluteZ, world.getSeed())
);
modifier.setBiome(absoluteX, y, absoluteZ, userDefinedBiome.registry());
}
}
}
} else {
// TODO: remove with feature flag once minestom fixed biome encoding
UserDefinedBiome userDefinedBiome = biomePool.getBiome(biomeProvider.getBiome(blockX, 100, blockZ, world.getSeed()));
modifier.fillBiome(userDefinedBiome.registry());
}
unit.fork(setter -> {
MinestomProtoWorld protoWorld = new MinestomProtoWorld(cache, x, z, world, setter);

View File

@ -48,7 +48,8 @@ public final class TerraMinestomWorld implements ServerWorld, WorldProperties {
long seed,
EntityFactory entityFactory,
BlockEntityFactory blockEntityFactory,
BiomeFactory factory
BiomeFactory factory,
boolean doFineGrainedBiomes
) {
this.instance = instance;
this.pack = pack;
@ -62,7 +63,8 @@ public final class TerraMinestomWorld implements ServerWorld, WorldProperties {
pack.getGeneratorProvider().newInstance(pack),
this,
pack,
new MinestomUserDefinedBiomePool(pack, new MinestomUserDefinedBiomeFactory())
new MinestomUserDefinedBiomePool(pack, factory),
doFineGrainedBiomes
);
this.entityFactory = entityFactory;