diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/TerraMinestomExample.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/TerraMinestomExample.java index bec43cc80..acc5abdfc 100644 --- a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/TerraMinestomExample.java +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/TerraMinestomExample.java @@ -1,15 +1,26 @@ package com.dfsek.terra.minestom; +import com.dfsek.terra.minestom.api.filter.ChunkFilter; +import com.dfsek.terra.minestom.api.filter.EvenChunkFilter; +import com.dfsek.terra.minestom.api.filter.NoFeaturesFilter; +import com.dfsek.terra.minestom.api.filter.NoTerrainFilter; +import com.dfsek.terra.minestom.api.filter.SpecificChunkFilter; +import com.dfsek.terra.minestom.api.filter.XFilter; +import com.dfsek.terra.minestom.api.filter.ZFilter; import com.dfsek.terra.minestom.world.TerraMinestomWorld; import com.dfsek.terra.minestom.world.TerraMinestomWorldBuilder; +import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; import net.minestom.server.command.builder.Command; +import net.minestom.server.command.builder.arguments.ArgumentLiteral; +import net.minestom.server.command.builder.arguments.number.ArgumentInteger; 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.PlayerSpawnEvent; import net.minestom.server.instance.Instance; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,20 +31,25 @@ import java.util.concurrent.atomic.AtomicInteger; public class TerraMinestomExample { private static final Logger logger = LoggerFactory.getLogger(TerraMinestomExample.class); private final MinecraftServer server = MinecraftServer.init(); - private final Instance instance = MinecraftServer.getInstanceManager().createInstanceContainer(); + private Instance instance = MinecraftServer.getInstanceManager().createInstanceContainer(); private TerraMinestomWorld world; - public void attachTerra() { + public void createNewInstance() { + instance = MinecraftServer.getInstanceManager().createInstanceContainer(); + } + + public void attachTerra(ChunkFilter filter) { world = TerraMinestomWorldBuilder.from(instance) .defaultPack() - .seed(0) +// .seed(0) + .filtered(filter) .attach(); } private void sendProgressBar(int current, int max) { - String left = "#".repeat((int) ((((float) current)/max) * 20)); + String left = "#".repeat((int) ((((float) current) / max) * 20)); String right = ".".repeat(20 - left.length()); - int percent = (int) (((float) current)/max * 100); + int percent = (int) (((float) current) / max * 100); String percentString = percent + "%"; percentString = " ".repeat(4 - percentString.length()) + percentString; String message = percentString + " |" + left + right + "| " + current + "/" + max; @@ -62,7 +78,7 @@ public class TerraMinestomExample { ); world.displayStats(); - } else if (left % 20 == 0) { + } else if(left % 20 == 0) { sendProgressBar(chunksLoading - left, chunksLoading); } }); @@ -87,6 +103,10 @@ public class TerraMinestomExample { .schedule(); } + public void addCommands() { + MinecraftServer.getCommandManager().register(new RegenerateCommand()); + } + public void bind() { logger.info("Starting server on port 25565"); server.start("localhost", 25565); @@ -94,10 +114,42 @@ public class TerraMinestomExample { public static void main(String[] args) { TerraMinestomExample example = new TerraMinestomExample(); - example.attachTerra(); + example.attachTerra(null); example.preloadWorldAndMeasure(); example.addScheduler(); example.addListeners(); + example.addCommands(); example.bind(); } + + public class RegenerateCommand extends Command { + public RegenerateCommand() { + super("regenerate"); + + ArgumentInteger cx = new ArgumentInteger("cx"); + ArgumentInteger cz = new ArgumentInteger("cz"); + + setDefaultExecutor((sender, context) -> regenerate(null)); + addSyntax((sender, context) -> regenerate(new NoFeaturesFilter()), new ArgumentLiteral("noFeatures")); + addSyntax((sender, context) -> regenerate(new NoTerrainFilter()), new ArgumentLiteral("noTerrain")); + addSyntax((sender, context) -> regenerate(new EvenChunkFilter()), new ArgumentLiteral("evenChunks")); + addSyntax((sender, context) -> regenerate(new SpecificChunkFilter(context.get(cx), context.get(cz))), new ArgumentLiteral("chunk"), cx, cz); + addSyntax((sender, context) -> regenerate(new XFilter(context.get(cx))), new ArgumentLiteral("x"), cx); + addSyntax((sender, context) -> regenerate(new ZFilter(context.get(cz))), new ArgumentLiteral("z"), cz); + } + + private void regenerate(@Nullable ChunkFilter filter) { + if (filter == null) { + instance.sendMessage(Component.text("Regenerating world without filter ")); + } else { + instance.sendMessage(Component.text("Regenerating world with filter " + filter.getClass().getSimpleName())); + } + createNewInstance(); + attachTerra(filter); + preloadWorldAndMeasure(); + MinecraftServer.getConnectionManager().getOnlinePlayers().forEach(player -> + player.setInstance(instance, new Pos(0, 100, 0)) + ); + } + } } diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/ChunkFilter.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/ChunkFilter.java new file mode 100644 index 000000000..a72ebcc6d --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/ChunkFilter.java @@ -0,0 +1,12 @@ +package com.dfsek.terra.minestom.api.filter; + +/** + * This interface defines a filter for determining whether terrain and features + * should be placed during chunk generation. Implementations of this interface + * can apply custom logic to selectively control terrain and feature placement + * in specific chunks for debugging purposes. + */ +public interface ChunkFilter { + boolean shouldPlaceTerrain(int x, int z); + boolean shouldPlaceFeatures(int x, int z); +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/EvenChunkFilter.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/EvenChunkFilter.java new file mode 100644 index 000000000..f97507ed1 --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/EvenChunkFilter.java @@ -0,0 +1,13 @@ +package com.dfsek.terra.minestom.api.filter; + +public class EvenChunkFilter implements ChunkFilter { + @Override + public boolean shouldPlaceTerrain(int x, int z) { + return x % 2 == 0 && z % 2 == 0; + } + + @Override + public boolean shouldPlaceFeatures(int x, int z) { + return x % 2 == 0 && z % 2 == 0; + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/NoFeaturesFilter.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/NoFeaturesFilter.java new file mode 100644 index 000000000..dbbdeb94d --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/NoFeaturesFilter.java @@ -0,0 +1,13 @@ +package com.dfsek.terra.minestom.api.filter; + +public class NoFeaturesFilter implements ChunkFilter { + @Override + public boolean shouldPlaceTerrain(int x, int z) { + return true; + } + + @Override + public boolean shouldPlaceFeatures(int x, int z) { + return false; + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/NoTerrainFilter.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/NoTerrainFilter.java new file mode 100644 index 000000000..671c746bd --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/NoTerrainFilter.java @@ -0,0 +1,13 @@ +package com.dfsek.terra.minestom.api.filter; + +public class NoTerrainFilter implements ChunkFilter { + @Override + public boolean shouldPlaceTerrain(int x, int z) { + return false; + } + + @Override + public boolean shouldPlaceFeatures(int x, int z) { + return true; + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/SpecificChunkFilter.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/SpecificChunkFilter.java new file mode 100644 index 000000000..cd1670188 --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/SpecificChunkFilter.java @@ -0,0 +1,21 @@ +package com.dfsek.terra.minestom.api.filter; + +public class SpecificChunkFilter implements ChunkFilter { + private final int x; + private final int z; + + public SpecificChunkFilter(int x, int z) { + this.x = x; + this.z = z; + } + + @Override + public boolean shouldPlaceTerrain(int x, int z) { + return this.x == x && this.z == z; + } + + @Override + public boolean shouldPlaceFeatures(int x, int z) { + return this.x == x && this.z == z; + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/XFilter.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/XFilter.java new file mode 100644 index 000000000..c282bc2a3 --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/XFilter.java @@ -0,0 +1,17 @@ +package com.dfsek.terra.minestom.api.filter; + +public class XFilter implements ChunkFilter { + private final int x; + + public XFilter(int x) { this.x = x; } + + @Override + public boolean shouldPlaceTerrain(int x, int z) { + return this.x == x; + } + + @Override + public boolean shouldPlaceFeatures(int x, int z) { + return this.x == x; + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/ZFilter.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/ZFilter.java new file mode 100644 index 000000000..39dfb054e --- /dev/null +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/api/filter/ZFilter.java @@ -0,0 +1,17 @@ +package com.dfsek.terra.minestom.api.filter; + +public class ZFilter implements ChunkFilter { + private final int z; + + public ZFilter(int z) { this.z = z; } + + @Override + public boolean shouldPlaceTerrain(int x, int z) { + return this.z == z; + } + + @Override + public boolean shouldPlaceFeatures(int x, int z) { + return this.z == z; + } +} diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/chunk/CachedChunk.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/chunk/CachedChunk.java index 5a57f9830..ed9ad8622 100644 --- a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/chunk/CachedChunk.java +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/chunk/CachedChunk.java @@ -5,6 +5,7 @@ import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.world.chunk.generation.ProtoChunk; import com.dfsek.terra.minestom.block.MinestomBlockState; + import net.minestom.server.instance.block.Block; import net.minestom.server.instance.generator.UnitModifier; import org.jetbrains.annotations.NotNull; @@ -20,9 +21,9 @@ public class CachedChunk implements ProtoChunk { this.maxHeight = maxHeight; this.blocks = new Block[16][maxHeight - minHeight + 1][16]; - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = 0; y < maxHeight - minHeight + 1; y++) { + for(int x = 0; x < 16; x++) { + for(int z = 0; z < 16; z++) { + for(int y = 0; y < maxHeight - minHeight + 1; y++) { blocks[x][y][z] = Block.AIR; } } diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/MinestomChunkGeneratorWrapper.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/MinestomChunkGeneratorWrapper.java index 061729c92..9daf2b60f 100644 --- a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/MinestomChunkGeneratorWrapper.java +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/MinestomChunkGeneratorWrapper.java @@ -3,6 +3,7 @@ package com.dfsek.terra.minestom.world; import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage; +import com.dfsek.terra.minestom.api.filter.ChunkFilter; import com.dfsek.terra.minestom.chunk.CachedChunk; import com.dfsek.terra.minestom.chunk.GeneratedChunkCache; @@ -16,10 +17,12 @@ public class MinestomChunkGeneratorWrapper implements Generator { private final GeneratedChunkCache cache; private final ChunkGenerator generator; private final TerraMinestomWorld world; + private final ChunkFilter filter; - public MinestomChunkGeneratorWrapper(ChunkGenerator generator, TerraMinestomWorld world) { + public MinestomChunkGeneratorWrapper(ChunkGenerator generator, TerraMinestomWorld world, ChunkFilter filter) { this.generator = generator; this.world = world; + this.filter = filter; this.cache = new GeneratedChunkCache(world.getDimensionType(), generator, world); } @@ -30,21 +33,21 @@ public class MinestomChunkGeneratorWrapper implements Generator { @Override public void generate(@NotNull GenerationUnit unit) { Point start = unit.absoluteStart(); - CachedChunk chunk = cache.at(start.chunkX(), start.chunkZ()); - chunk.writeRelative(unit.modifier()); - unit.fork(setter -> { - MinestomProtoWorld protoWorld = new MinestomProtoWorld( - cache, - start.chunkX(), - start.chunkZ(), - world, - setter - ); + int x = start.chunkX(); + int z = start.chunkZ(); + CachedChunk chunk = cache.at(x, z); + if(filter == null || filter.shouldPlaceTerrain(x, z)) + chunk.writeRelative(unit.modifier()); - for(GenerationStage stage : world.getPack().getStages()) { - stage.populate(protoWorld); - } - }); + if(filter == null || filter.shouldPlaceFeatures(x, z)) { + unit.fork(setter -> { + MinestomProtoWorld protoWorld = new MinestomProtoWorld(cache, x, z, world, setter); + + for(GenerationStage stage : world.getPack().getStages()) { + stage.populate(protoWorld); + } + }); + } } public void displayStats() { diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/MinestomProtoWorld.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/MinestomProtoWorld.java index b3cbb768d..61d1482f6 100644 --- a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/MinestomProtoWorld.java +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/MinestomProtoWorld.java @@ -56,16 +56,12 @@ public class MinestomProtoWorld implements ProtoWorld { @Override public void setBlockState(int x, int y, int z, BlockState data, boolean physics) { - int cx = x >> 4; - int cz = y >> 4; modifier.setBlock(x, y, z, (Block) data.getHandle()); - cache.at(cx, cz) - .setBlock(x & 15, y, z & 15, data); } @Override public Entity spawnEntity(double x, double y, double z, EntityType entityType) { - TerraMinestomWorld world = (TerraMinestomWorld) this.world; + TerraMinestomWorld world = this.world; DeferredMinestomEntity entity = new DeferredMinestomEntity(x, y, z, entityType, world); world.enqueueEntitySpawn(entity); return entity; diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorld.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorld.java index 671ad8e90..847b40eac 100644 --- a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorld.java +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorld.java @@ -5,7 +5,6 @@ import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.entity.Entity; 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.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.chunk.Chunk; @@ -16,6 +15,7 @@ import com.dfsek.terra.api.world.info.WorldProperties; import com.dfsek.terra.minestom.api.EntityFactory; import com.dfsek.terra.minestom.block.MinestomBlockState; +import com.dfsek.terra.minestom.api.filter.ChunkFilter; import com.dfsek.terra.minestom.entity.DeferredMinestomEntity; import com.dfsek.terra.minestom.entity.MinestomEntity; @@ -24,9 +24,6 @@ import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; import net.minestom.server.world.DimensionType; -import java.util.ArrayList; -import java.util.HashMap; - public final class TerraMinestomWorld implements ServerWorld, WorldProperties { private final Instance instance; @@ -36,7 +33,7 @@ public final class TerraMinestomWorld implements ServerWorld, WorldProperties { private final MinestomChunkGeneratorWrapper wrapper; private final EntityFactory factory; - public TerraMinestomWorld(Instance instance, ConfigPack pack, long seed, EntityFactory factory) { + public TerraMinestomWorld(Instance instance, ConfigPack pack, long seed, EntityFactory factory, ChunkFilter filter) { this.instance = instance; this.pack = pack; this.seed = seed; @@ -45,7 +42,8 @@ public final class TerraMinestomWorld implements ServerWorld, WorldProperties { this.wrapper = new MinestomChunkGeneratorWrapper( pack.getGeneratorProvider().newInstance(pack), - this + this, + filter ); this.factory = factory; diff --git a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorldBuilder.java b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorldBuilder.java index 5a018ef2d..eba7621a4 100644 --- a/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorldBuilder.java +++ b/platforms/minestom/src/main/java/com/dfsek/terra/minestom/world/TerraMinestomWorldBuilder.java @@ -6,9 +6,11 @@ import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.minestom.MinestomPlatform; import com.dfsek.terra.minestom.api.EntityFactory; +import com.dfsek.terra.minestom.api.filter.ChunkFilter; import com.dfsek.terra.minestom.entity.DefaultEntityFactory; import net.minestom.server.MinecraftServer; import net.minestom.server.instance.Instance; +import org.jetbrains.annotations.Nullable; import java.util.Random; import java.util.function.Function; @@ -19,6 +21,7 @@ public class TerraMinestomWorldBuilder { private ConfigPack pack; private long seed = new Random().nextLong(); private EntityFactory factory = new DefaultEntityFactory(); + private ChunkFilter filter; private TerraMinestomWorldBuilder(Instance instance) { this.instance = instance; } @@ -64,7 +67,12 @@ public class TerraMinestomWorldBuilder { return this; } + public TerraMinestomWorldBuilder filtered(@Nullable ChunkFilter filter) { + this.filter = filter; + return this; + } + public TerraMinestomWorld attach() { - return new TerraMinestomWorld(instance, pack, seed, factory); + return new TerraMinestomWorld(instance, pack, seed, factory, filter); } }