From 6e51e3d3cf1b4d8fb8007cff46647f7465e8899e Mon Sep 17 00:00:00 2001 From: GreatWyrm Date: Sat, 31 Dec 2022 19:05:58 -0800 Subject: [PATCH 1/3] Add the ability to paste into an instance, and optionally load chunks when doing so --- .../net/hollowcube/util/schem/Schematic.java | 35 +++++++++++++++++++ .../schem/src/test/java/SchemPasterTest.java | 25 +++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 modules/schem/src/test/java/SchemPasterTest.java diff --git a/modules/schem/src/main/java/net/hollowcube/util/schem/Schematic.java b/modules/schem/src/main/java/net/hollowcube/util/schem/Schematic.java index 88f63c2..66a09c2 100644 --- a/modules/schem/src/main/java/net/hollowcube/util/schem/Schematic.java +++ b/modules/schem/src/main/java/net/hollowcube/util/schem/Schematic.java @@ -2,6 +2,8 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; +import net.minestom.server.instance.Chunk; +import net.minestom.server.instance.Instance; import net.minestom.server.instance.batch.BatchOption; import net.minestom.server.instance.batch.RelativeBlockBatch; import net.minestom.server.instance.block.Block; @@ -10,8 +12,10 @@ import org.jetbrains.annotations.Nullable; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; import java.util.Map; +import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; import java.util.function.Function; @@ -50,6 +54,37 @@ public Point offset(Rotation rotation) { return rotatePos(offset, rotation); } + public @NotNull RelativeBlockBatch applyToInstance(@NotNull Instance instance, @NotNull Point startPoint, boolean loadChunks, @NotNull Rotation rotation, @Nullable Function blockModifier) { + RelativeBlockBatch batch = build(rotation, blockModifier); + if (loadChunks) { + Point min = startPoint.add(offset()); + Point max = min.add(size()); + int chunkXStart = min.chunkX(); + int chunkXSize = max.chunkX() - min.chunkX() + 1; + int chunkZStart = min.chunkZ(); + int chunkZSize = max.chunkZ() - min.chunkZ() + 1; + ArrayList> chunksToLoad = new ArrayList<>(); + for (int i = chunkXStart; i < chunkXStart + chunkXSize; i++) { + for (int j = chunkZStart; j < chunkZStart + chunkZSize; j++) { + chunksToLoad.add(instance.loadOptionalChunk(i, j)); + } + } + CompletableFuture.allOf(chunksToLoad.toArray(new CompletableFuture[0])).thenRun(() -> batch.apply(instance, startPoint, null)).thenRun(() -> { + for (int i = chunkXStart; i < chunkXStart + chunkXSize; i++) { + for (int j = chunkZStart; j < chunkZStart + chunkZSize; j++) { + Chunk chunk = instance.getChunk(i, j); + if(chunk != null && chunk.isLoaded() && chunk.getViewers().isEmpty()) { + instance.unloadChunk(chunk); + } + } + } + }); + } else { + batch.apply(instance, startPoint, null); + } + return batch; + } + /** * Convert the schematic into a {@link RelativeBlockBatch} which can be applied to an instance. * The schematic can be rotated around its {@link #offset()} before placement. diff --git a/modules/schem/src/test/java/SchemPasterTest.java b/modules/schem/src/test/java/SchemPasterTest.java new file mode 100644 index 0000000..6e8b827 --- /dev/null +++ b/modules/schem/src/test/java/SchemPasterTest.java @@ -0,0 +1,25 @@ +import net.hollowcube.util.schem.Rotation; +import net.hollowcube.util.schem.Schematic; +import net.hollowcube.util.schem.SchematicReader; +import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.instance.Instance; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Path; + +public class SchemPasterTest { + + @Test + public void testSchemPaste() { + MinecraftServer.init(); + Instance instance = MinecraftServer.getInstanceManager().createInstanceContainer(); + try { + Schematic big = SchematicReader.read(Path.of("src/test/resources/big.schem")); + big.applyToInstance(instance, new Pos(15, 40, 15), true, Rotation.NONE, null); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} From 834cda02213a8f004f96b9284a0b2b0fb8f4129a Mon Sep 17 00:00:00 2001 From: GreatWyrm Date: Mon, 20 Feb 2023 16:40:15 -0800 Subject: [PATCH 2/3] Change return type to completable future, some attempt at fixing the test --- .../net/hollowcube/util/schem/Schematic.java | 7 +++--- .../schem/src/test/java/SchemPasterTest.java | 24 +++++++++++++++---- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/modules/schem/src/main/java/net/hollowcube/util/schem/Schematic.java b/modules/schem/src/main/java/net/hollowcube/util/schem/Schematic.java index 66a09c2..9db6ade 100644 --- a/modules/schem/src/main/java/net/hollowcube/util/schem/Schematic.java +++ b/modules/schem/src/main/java/net/hollowcube/util/schem/Schematic.java @@ -54,7 +54,7 @@ public Point offset(Rotation rotation) { return rotatePos(offset, rotation); } - public @NotNull RelativeBlockBatch applyToInstance(@NotNull Instance instance, @NotNull Point startPoint, boolean loadChunks, @NotNull Rotation rotation, @Nullable Function blockModifier) { + public @NotNull CompletableFuture applyToInstance(@NotNull Instance instance, @NotNull Point startPoint, boolean loadChunks, @NotNull Rotation rotation, @Nullable Function blockModifier) { RelativeBlockBatch batch = build(rotation, blockModifier); if (loadChunks) { Point min = startPoint.add(offset()); @@ -69,7 +69,7 @@ public Point offset(Rotation rotation) { chunksToLoad.add(instance.loadOptionalChunk(i, j)); } } - CompletableFuture.allOf(chunksToLoad.toArray(new CompletableFuture[0])).thenRun(() -> batch.apply(instance, startPoint, null)).thenRun(() -> { + return CompletableFuture.allOf(chunksToLoad.toArray(new CompletableFuture[0])).thenRun(() -> batch.apply(instance, startPoint, null)).thenRun(() -> { for (int i = chunkXStart; i < chunkXStart + chunkXSize; i++) { for (int j = chunkZStart; j < chunkZStart + chunkZSize; j++) { Chunk chunk = instance.getChunk(i, j); @@ -80,9 +80,8 @@ public Point offset(Rotation rotation) { } }); } else { - batch.apply(instance, startPoint, null); + return CompletableFuture.runAsync(() -> batch.apply(instance, startPoint, null)); } - return batch; } /** diff --git a/modules/schem/src/test/java/SchemPasterTest.java b/modules/schem/src/test/java/SchemPasterTest.java index 6e8b827..23e4e03 100644 --- a/modules/schem/src/test/java/SchemPasterTest.java +++ b/modules/schem/src/test/java/SchemPasterTest.java @@ -1,25 +1,39 @@ import net.hollowcube.util.schem.Rotation; import net.hollowcube.util.schem.Schematic; import net.hollowcube.util.schem.SchematicReader; -import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; +import net.minestom.server.event.instance.InstanceChunkLoadEvent; +import net.minestom.server.event.instance.InstanceChunkUnloadEvent; import net.minestom.server.instance.Instance; +import net.minestom.server.test.Env; +import net.minestom.server.test.EnvTest; import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@EnvTest public class SchemPasterTest { @Test - public void testSchemPaste() { - MinecraftServer.init(); - Instance instance = MinecraftServer.getInstanceManager().createInstanceContainer(); + public void testSchemPaste(Env env) { + AtomicInteger chunksLoaded = new AtomicInteger(); + AtomicInteger chunksUnloaded = new AtomicInteger(); + Instance instance = env.createFlatInstance(); + instance.eventNode().addListener(InstanceChunkLoadEvent.class, event -> chunksLoaded.getAndIncrement()); + instance.eventNode().addListener(InstanceChunkUnloadEvent.class, event -> chunksUnloaded.getAndIncrement()); try { Schematic big = SchematicReader.read(Path.of("src/test/resources/big.schem")); - big.applyToInstance(instance, new Pos(15, 40, 15), true, Rotation.NONE, null); + CompletableFuture pasteProcess = big.applyToInstance(instance, new Pos(15, 40, 15), true, Rotation.NONE, null); + pasteProcess.join(); } catch (IOException e) { throw new RuntimeException(e); } + assertEquals(5, chunksLoaded.get()); + assertEquals(chunksLoaded.get(), chunksUnloaded.get()); } } From e934e9cc04e201b2c4154e0dd450d0b7f627fc7c Mon Sep 17 00:00:00 2001 From: GreatWyrm Date: Wed, 22 Feb 2023 12:16:07 -0800 Subject: [PATCH 3/3] Fix number of chunks loaded --- modules/schem/src/test/java/SchemPasterTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/schem/src/test/java/SchemPasterTest.java b/modules/schem/src/test/java/SchemPasterTest.java index 23e4e03..184b3c5 100644 --- a/modules/schem/src/test/java/SchemPasterTest.java +++ b/modules/schem/src/test/java/SchemPasterTest.java @@ -33,7 +33,7 @@ public void testSchemPaste(Env env) { } catch (IOException e) { throw new RuntimeException(e); } - assertEquals(5, chunksLoaded.get()); + assertEquals(2, chunksLoaded.get()); assertEquals(chunksLoaded.get(), chunksUnloaded.get()); } }