fix: generation stages not being able to reference eachother

This commit is contained in:
Christian Bergschneider
2025-06-02 00:34:48 +02:00
parent 5dff25670c
commit 5e1c9d8ebe
9 changed files with 86 additions and 23 deletions
@@ -122,12 +122,15 @@ public class TerraMinestomExample {
private void regenerate() { private void regenerate() {
instance.sendMessage(Component.text("Regenerating world")); instance.sendMessage(Component.text("Regenerating world"));
Instance oldInstance = instance;
createNewInstance(); createNewInstance();
attachTerra(); attachTerra();
preloadWorldAndMeasure(); preloadWorldAndMeasure();
MinecraftServer.getConnectionManager().getOnlinePlayers().forEach(player -> MinecraftServer.getConnectionManager().getOnlinePlayers().forEach(player ->
player.setInstance(instance, new Pos(0, 100, 0)) player.setInstance(instance, new Pos(0, 100, 0))
); );
MinecraftServer.getInstanceManager().unregisterInstance(oldInstance);
} }
} }
} }
@@ -2,16 +2,17 @@ package com.dfsek.terra.minestom.biome;
import com.dfsek.terra.api.world.biome.PlatformBiome; import com.dfsek.terra.api.world.biome.PlatformBiome;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.world.biome.Biome; import net.minestom.server.world.biome.Biome;
public class MinestomBiome implements PlatformBiome { public class MinestomBiome implements PlatformBiome {
private final Biome biome; private final DynamicRegistry.Key<Biome> biome;
public MinestomBiome(Biome biome) { this.biome = biome; } public MinestomBiome(DynamicRegistry.Key<Biome> biome) { this.biome = biome; }
@Override @Override
public Biome getHandle() { public DynamicRegistry.Key<Biome> getHandle() {
return biome; return biome;
} }
} }
@@ -8,23 +8,19 @@ import com.dfsek.tectonic.api.loader.type.TypeLoader;
import com.dfsek.terra.api.world.biome.PlatformBiome; import com.dfsek.terra.api.world.biome.PlatformBiome;
import net.kyori.adventure.key.Key; import net.kyori.adventure.key.Key;
import net.minestom.server.MinecraftServer;
import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.world.biome.Biome; import org.intellij.lang.annotations.Subst;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.lang.reflect.AnnotatedType; import java.lang.reflect.AnnotatedType;
public class MinestomBiomeLoader implements TypeLoader<PlatformBiome> { public class MinestomBiomeLoader implements TypeLoader<PlatformBiome> {
private final DynamicRegistry<Biome> biomeRegistry = MinecraftServer.getBiomeRegistry();
@Override @Override
public PlatformBiome load(@NotNull AnnotatedType annotatedType, @NotNull Object o, @NotNull ConfigLoader configLoader, public PlatformBiome load(@NotNull AnnotatedType annotatedType, @NotNull Object o, @NotNull ConfigLoader configLoader,
DepthTracker depthTracker) throws LoadException { DepthTracker depthTracker) throws LoadException {
@Subst("name:value")
String id = (String) o; String id = (String) o;
Key key = Key.key(id); Key key = Key.key(id);
Biome biome = biomeRegistry.get(key); return new MinestomBiome(DynamicRegistry.Key.of(key));
if(biome == null) throw new LoadException("Biome %s does not exist in registry".formatted(id), depthTracker);
return new MinestomBiome(biome);
} }
} }
@@ -3,10 +3,16 @@ package com.dfsek.terra.minestom.chunk;
import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.util.Column;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.chunk.generation.ProtoChunk; import com.dfsek.terra.api.world.chunk.generation.ProtoChunk;
import com.dfsek.terra.minestom.biome.MinestomBiome;
import com.dfsek.terra.minestom.block.MinestomBlockState; import com.dfsek.terra.minestom.block.MinestomBlockState;
import net.minestom.server.coordinate.Point;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.generator.GenerationUnit;
import net.minestom.server.instance.generator.UnitModifier; import net.minestom.server.instance.generator.UnitModifier;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -22,13 +22,15 @@ public class GeneratedChunkCache {
private final ServerWorld world; private final ServerWorld world;
private final BiomeProvider biomeProvider; private final BiomeProvider biomeProvider;
public GeneratedChunkCache(DimensionType dimensionType, ChunkGenerator generator, ServerWorld world) { public GeneratedChunkCache(DimensionType dimensionType, ChunkGenerator generator, ServerWorld world, BiomeProvider biomeProvider) {
this.dimensionType = dimensionType; this.dimensionType = dimensionType;
this.generator = generator; this.generator = generator;
this.world = world; this.world = world;
this.biomeProvider = world.getBiomeProvider(); this.biomeProvider = biomeProvider;
this.cache = Caffeine.newBuilder().maximumSize(128).recordStats().build( this.cache = Caffeine.newBuilder()
(Pair<Integer, Integer> key) -> generateChunk(key.getLeft(), key.getRight())); .maximumSize(128)
.recordStats()
.build((Pair<Integer, Integer> key) -> generateChunk(key.getLeft(), key.getRight()));
} }
private CachedChunk generateChunk(int x, int z) { private CachedChunk generateChunk(int x, int z) {
@@ -39,8 +41,13 @@ public class GeneratedChunkCache {
public void displayStats() { public void displayStats() {
CacheStats stats = cache.stats(); CacheStats stats = cache.stats();
log.info("Avg load time: {}ms | Hit rate: {}% | Load Count: {}", stats.averageLoadPenalty(), stats.hitRate() * 100, log.info("Avg load time: %.4fms | Hit rate: %3.4f%% | Load Count: %d"
stats.loadCount()); .formatted(
stats.averageLoadPenalty() / 1000000f,
stats.hitRate() * 100,
stats.loadCount()
)
);
} }
public CachedChunk at(int x, int z) { public CachedChunk at(int x, int z) {
@@ -1,30 +1,41 @@
package com.dfsek.terra.minestom.world; package com.dfsek.terra.minestom.world;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.world.biome.PlatformBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage; import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage;
import com.dfsek.terra.api.world.chunk.generation.util.GeneratorWrapper; import com.dfsek.terra.api.world.chunk.generation.util.GeneratorWrapper;
import com.dfsek.terra.minestom.biome.MinestomBiome;
import com.dfsek.terra.minestom.chunk.CachedChunk; import com.dfsek.terra.minestom.chunk.CachedChunk;
import com.dfsek.terra.minestom.chunk.GeneratedChunkCache; import com.dfsek.terra.minestom.chunk.GeneratedChunkCache;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.instance.generator.GenerationUnit; import net.minestom.server.instance.generator.GenerationUnit;
import net.minestom.server.instance.generator.Generator; import net.minestom.server.instance.generator.Generator;
import net.minestom.server.instance.generator.UnitModifier;
import net.minestom.server.registry.DynamicRegistry;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrapper { public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrapper {
private final GeneratedChunkCache cache; private final GeneratedChunkCache cache;
private ChunkGenerator generator; private ChunkGenerator generator;
private final TerraMinestomWorld world; private final TerraMinestomWorld world;
private final BiomeProvider biomeProvider;
private ConfigPack pack; private ConfigPack pack;
public MinestomChunkGeneratorWrapper(ChunkGenerator generator, TerraMinestomWorld world, ConfigPack pack) { public MinestomChunkGeneratorWrapper(Platform platform, ChunkGenerator generator, TerraMinestomWorld world, ConfigPack pack) {
this.generator = generator; this.generator = generator;
this.world = world; this.world = world;
this.pack = pack; this.pack = pack;
this.cache = new GeneratedChunkCache(world.getDimensionType(), generator, world);
biomeProvider = pack.getBiomeProvider().caching(platform);
this.cache = new GeneratedChunkCache(world.getDimensionType(), generator, world, biomeProvider);
} }
public ChunkGenerator getGenerator() { public ChunkGenerator getGenerator() {
@@ -36,14 +47,36 @@ public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrappe
Point start = unit.absoluteStart(); Point start = unit.absoluteStart();
int x = start.chunkX(); int x = start.chunkX();
int z = start.chunkZ(); int z = start.chunkZ();
int blockX = start.blockX();
int blockZ = start.blockZ();
CachedChunk chunk = cache.at(x, z); CachedChunk chunk = cache.at(x, z);
chunk.writeRelative(unit.modifier()); UnitModifier modifier = unit.modifier();
chunk.writeRelative(modifier);
// for(int dx = 0; dx < 16; dx++) {
// for(int dz = 0; dz < 16; dz++) {
// int globalX = dx + blockX;
// int globalZ = dz + blockZ;
// biomeProvider.getColumn(globalX, globalZ, world).forEach((y, biome) -> {
// MinestomBiome platformBiome = (MinestomBiome) biome.getPlatformBiome();
// modifier.setBiome(globalX, 0, globalZ, DynamicRegistry.Key.of("minecraft:the_void"));
// });
// }
// }
unit.fork(setter -> { unit.fork(setter -> {
MinestomProtoWorld protoWorld = new MinestomProtoWorld(cache, x, z, world, setter); MinestomProtoWorld protoWorld = new MinestomProtoWorld(cache, x, z, world, setter);
var stages = world.getPack().getStages();
if(x==0 && z==0) {
System.out.println(stages);
System.out.println(protoWorld.getBlockState(-4, 73, -6).getAsString());
}
for(GenerationStage stage : world.getPack().getStages()) { for(GenerationStage stage : world.getPack().getStages()) {
stage.populate(protoWorld); stage.populate(protoWorld);
if(x==0 && z==0) System.out.println(protoWorld.getBlockState(-4, 73, -6).getAsString());
} }
}); });
} }
@@ -5,6 +5,7 @@ import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.entity.Entity; import com.dfsek.terra.api.entity.Entity;
import com.dfsek.terra.api.entity.EntityType; import com.dfsek.terra.api.entity.EntityType;
import com.dfsek.terra.api.util.generic.pair.Pair;
import com.dfsek.terra.api.world.ServerWorld; import com.dfsek.terra.api.world.ServerWorld;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
@@ -17,6 +18,11 @@ import com.dfsek.terra.minestom.entity.DeferredMinestomEntity;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.Block.Setter; import net.minestom.server.instance.block.Block.Setter;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.HashSet;
import java.util.WeakHashMap;
public class MinestomProtoWorld implements ProtoWorld { public class MinestomProtoWorld implements ProtoWorld {
private final GeneratedChunkCache cache; private final GeneratedChunkCache cache;
@@ -51,6 +57,10 @@ public class MinestomProtoWorld implements ProtoWorld {
@Override @Override
public void setBlockState(int x, int y, int z, BlockState data, boolean physics) { public void setBlockState(int x, int y, int z, BlockState data, boolean physics) {
modifier.setBlock(x, y, z, (Block) data.getHandle()); modifier.setBlock(x, y, z, (Block) data.getHandle());
int chunkX = x >> 4;
int chunkZ = z >> 4;
CachedChunk chunk = cache.at(chunkX, chunkZ);
chunk.setBlock(x & 15, y, z & 15, data);
} }
@Override @Override
@@ -13,6 +13,7 @@ import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
import com.dfsek.terra.api.world.info.WorldProperties; import com.dfsek.terra.api.world.info.WorldProperties;
import com.dfsek.terra.minestom.TerraMinestomPlatform;
import com.dfsek.terra.minestom.api.BlockEntityFactory; import com.dfsek.terra.minestom.api.BlockEntityFactory;
import com.dfsek.terra.minestom.api.EntityFactory; import com.dfsek.terra.minestom.api.EntityFactory;
import com.dfsek.terra.minestom.block.MinestomBlockState; import com.dfsek.terra.minestom.block.MinestomBlockState;
@@ -37,8 +38,14 @@ public final class TerraMinestomWorld implements ServerWorld, WorldProperties {
private final EntityFactory entityFactory; private final EntityFactory entityFactory;
private final BlockEntityFactory blockEntityFactory; private final BlockEntityFactory blockEntityFactory;
public TerraMinestomWorld(Instance instance, ConfigPack pack, long seed, EntityFactory entityFactory, public TerraMinestomWorld(
BlockEntityFactory blockEntityFactory) { TerraMinestomPlatform platform,
Instance instance,
ConfigPack pack,
long seed,
EntityFactory entityFactory,
BlockEntityFactory blockEntityFactory
) {
this.instance = instance; this.instance = instance;
this.pack = pack; this.pack = pack;
this.seed = seed; this.seed = seed;
@@ -46,7 +53,7 @@ public final class TerraMinestomWorld implements ServerWorld, WorldProperties {
this.dimensionType = MinecraftServer.getDimensionTypeRegistry().get(instance.getDimensionType()); this.dimensionType = MinecraftServer.getDimensionTypeRegistry().get(instance.getDimensionType());
this.blockEntityFactory = blockEntityFactory; this.blockEntityFactory = blockEntityFactory;
this.wrapper = new MinestomChunkGeneratorWrapper(pack.getGeneratorProvider().newInstance(pack), this, pack); this.wrapper = new MinestomChunkGeneratorWrapper(platform, pack.getGeneratorProvider().newInstance(pack), this, pack);
this.entityFactory = entityFactory; this.entityFactory = entityFactory;
instance.setGenerator(this.wrapper); instance.setGenerator(this.wrapper);
@@ -66,6 +66,6 @@ public class TerraMinestomWorldBuilder {
} }
public TerraMinestomWorld attach() { public TerraMinestomWorld attach() {
return new TerraMinestomWorld(instance, pack, seed, entityFactory, blockEntityFactory); return new TerraMinestomWorld(platform, instance, pack, seed, entityFactory, blockEntityFactory);
} }
} }