From e47fb3c4bd2ac56011ad8d885cd2845adfd2dbe6 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Wed, 7 Jul 2021 17:37:08 +0300 Subject: [PATCH] Added surface features. Tree generation is currently broken! - Added SurfaceFeature - Used to generate chunk features - Added SurfaceTopLayerFeature - A superclass for features that are only concerned with editing the surface - Added grass, temporary bushes and temporary trees - Bushes and trees do not generate properly due to bugs - Added Test:TemporaryLeaves - Added SurfaceWorld (a GenericWritableWorld wrapper) - Added some unit tests for rotation utilities - Fixed a whole lot of bugs --- .../common/world/generic/ChunkSet.java | 3 + .../common/world/generic/GenericChunk.java | 6 +- .../common/world/generic/GenericChunks.java | 19 ++- .../progressia/test/TestBushFeature.java | 47 +++++-- .../progressia/test/TestChunkCodec.java | 2 - .../windcorp/progressia/test/TestContent.java | 3 + .../progressia/test/TestGrassFeature.java | 68 +++++++++ .../progressia/test/TestTreeFeature.java | 103 ++++++++++++++ .../gen/planet/PlanetFeatureGenerator.java | 7 +- .../gen/planet/PlanetTerrainGenerator.java | 2 + .../test/gen/planet/TestPlanetGenerator.java | 3 +- .../test/gen/surface/SurfaceFeature.java | 130 ++++++++++-------- .../gen/surface/SurfaceFeatureGenerator.java | 2 +- .../gen/surface/SurfaceTopLayerFeature.java | 58 ++++++++ .../test/gen/surface/SurfaceWorld.java | 48 ++++--- .../textures/blocks/TemporaryLeaves.png | Bin 0 -> 13841 bytes .../textures/items/MoonTypeIceCream.png | Bin 0 -> 705 bytes .../generic/GenericChunkRotationsTest.java | 83 +++++++++++ .../common/world/rels/AxisRotationsTest.java | 100 ++++++++++++++ 19 files changed, 587 insertions(+), 97 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java create mode 100644 src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java create mode 100644 src/main/resources/assets/textures/blocks/TemporaryLeaves.png create mode 100644 src/main/resources/assets/textures/items/MoonTypeIceCream.png create mode 100644 src/test/java/ru/windcorp/progressia/common/world/generic/GenericChunkRotationsTest.java create mode 100644 src/test/java/ru/windcorp/progressia/common/world/rels/AxisRotationsTest.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java index 6f26ef0..199e780 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java @@ -56,6 +56,7 @@ public interface ChunkSet extends Iterable { default boolean contains(int x, int y, int z) { Vec3i v = Vectors.grab3i(); + v.set(x, y, z); boolean result = contains(v); Vectors.release(v); return result; @@ -63,6 +64,7 @@ public interface ChunkSet extends Iterable { default boolean add(int x, int y, int z) { Vec3i v = Vectors.grab3i(); + v.set(x, y, z); boolean result = add(v); Vectors.release(v); return result; @@ -70,6 +72,7 @@ public interface ChunkSet extends Iterable { default boolean remove(int x, int y, int z) { Vec3i v = Vectors.grab3i(); + v.set(x, y, z); boolean result = remove(v); Vectors.release(v); return result; diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index 0748a34..3643564 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -106,7 +106,11 @@ public interface GenericChunk< boolean hasTiles(Vec3i blockInChunk, BlockFace face); default Vec3i resolve(Vec3i relativeCoords, Vec3i output) { - return GenericChunks.resolve(relativeCoords, output, getUp()); + return GenericChunks.resolve(relativeCoords, getUp(), output); + } + + default Vec3i relativize(Vec3i absoluteCoords, Vec3i output) { + return GenericChunks.relativize(absoluteCoords, getUp(), output); } default B getBlockRel(Vec3i relativeBlockInChunk) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java index ac97578..3d65785 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java @@ -29,7 +29,7 @@ import ru.windcorp.progressia.common.world.rels.AxisRotations; public class GenericChunks { - public static Vec3i resolve(Vec3i relativeCoords, Vec3i output, AbsFace up) { + public static Vec3i resolve(Vec3i relativeCoords, AbsFace up, Vec3i output) { if (output == null) { output = new Vec3i(); } @@ -46,6 +46,23 @@ public class GenericChunks { return output; } + public static Vec3i relativize(Vec3i absoluteCoords, AbsFace up, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + final int offset = GenericChunk.BLOCKS_PER_CHUNK - 1; + + output.set(absoluteCoords.x, absoluteCoords.y, absoluteCoords.z); + output.mul(2).sub(offset); + + AxisRotations.relativize(output, up, output); + + output.add(offset).div(2); + + return output; + } + private static int getBorderHits(Vec3i blockInChunk) { int hits = 0; diff --git a/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java b/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java index 9e99314..50a56aa 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java +++ b/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java @@ -18,28 +18,49 @@ package ru.windcorp.progressia.test; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.test.gen.surface.SurfaceFeature; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; +import ru.windcorp.progressia.test.gen.surface.SurfaceTopLayerFeature; import ru.windcorp.progressia.test.gen.surface.SurfaceWorld; -public class TestBushFeature extends SurfaceFeature { +public class TestBushFeature extends SurfaceTopLayerFeature { public TestBushFeature(String id) { super(id); } - - @Override - public void process(SurfaceWorld world, Request request) { - BlockData block = BlockDataRegistry.getInstance().get("Test:Log"); - - Vec3i location = new Vec3i(request.getRandom().nextInt(ChunkData.BLOCKS_PER_CHUNK), request.getRandom().nextInt(ChunkData.BLOCKS_PER_CHUNK), request.getRandom().nextInt(ChunkData.BLOCKS_PER_CHUNK)).add(request.getMin()); - if (world.getBlockSfc(location) == BlockDataRegistry.getInstance().get("Test:Air")) { - - world.setBlockSfc(location, block, false); - + + private void tryToSetLeaves(SurfaceWorld world, Vec3i posSfc, BlockData leaves) { + if (world.getBlockSfc(posSfc).getId().equals("Test:Air")) { + world.setBlockSfc(posSfc, leaves, false); } } + + @Override + protected void processTopBlock(SurfaceWorld world, Request request, Vec3i topBlock) { + if (request.getRandom().nextInt(10*10) > 0) return; + + Vec3i center = topBlock.add_(0, 0, 1); + + BlockData log = BlockDataRegistry.getInstance().get("Test:Log"); + BlockData leaves = BlockDataRegistry.getInstance().get("Test:TemporaryLeaves"); + + world.setBlockSfc(center, log, false); + + VectorUtil.iterateCuboidAround(center.x, center.y, center.z, 3, 3, 3, p -> { + tryToSetLeaves(world, p, leaves); + }); + + VectorUtil.iterateCuboidAround(center.x, center.y, center.z, 5, 5, 1, p -> { + tryToSetLeaves(world, p, leaves); + }); + } + + @Override + protected boolean isSolid(SurfaceWorld world, Vec3i surfaceBlockInWorld) { + return BlockLogicRegistry.getInstance().get(world.getBlockSfc(surfaceBlockInWorld).getId()).isSolid(RelFace.UP); + } } diff --git a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java index 0f4dcd2..caba6ea 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java +++ b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java @@ -93,8 +93,6 @@ public class TestChunkCodec extends ChunkCodec { ChunkData chunk = new ChunkData(position, world); - assert chunk.getUp() == ru.windcorp.progressia.server.ServerState.getInstance().getWorld().getData().getChunk(position).getUp(); - readBlocks(input, blockPalette, chunk); readTiles(input, tilePalette, chunk); diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index e65ae68..0c78b35 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -140,6 +140,9 @@ public class TestContent { ) ); register(new BlockLogic("Test:Log")); + register(new BlockData("Test:TemporaryLeaves")); + register(new BlockRenderTransparentCube("Test:TemporaryLeaves", getBlockTexture("TemporaryLeaves"))); + register(new TestBlockLogicGlass("Test:TemporaryLeaves")); // Sic, using Glass logic for leaves because Test register(new BlockData("Test:WoodenPlank")); register(new BlockRenderOpaqueCube("Test:WoodenPlank", getBlockTexture("WoodenPlank"))); diff --git a/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java b/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java new file mode 100644 index 0000000..3689998 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java @@ -0,0 +1,68 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test; + +import java.util.Set; + +import com.google.common.collect.ImmutableSet; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.common.world.tile.TileDataRegistry; +import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; +import ru.windcorp.progressia.test.gen.surface.SurfaceTopLayerFeature; +import ru.windcorp.progressia.test.gen.surface.SurfaceWorld; + +public class TestGrassFeature extends SurfaceTopLayerFeature { + + private static final Set WHITELIST = ImmutableSet.of( + "Test:Dirt", + "Test:Stone", + "Test:GraniteMonolith", + "Test:GraniteCracked", + "Test:GraniteGravel" + ); + + public TestGrassFeature(String id) { + super(id); + } + + @Override + protected void processTopBlock(SurfaceWorld world, Request request, Vec3i topBlock) { + if (!WHITELIST.contains(world.getBlockSfc(topBlock).getId())) { + return; + } + + TileData grass = TileDataRegistry.getInstance().get("Test:Grass"); + + for (RelFace face : RelFace.getFaces()) { + if (face == RelFace.DOWN) continue; + + if (BlockLogicRegistry.getInstance().get(world.getBlockSfc(topBlock.add_(face.getRelVector())).getId()).isTransparent()) { + world.getTilesSfc(topBlock, face).addFarthest(grass); + } + } + } + + @Override + protected boolean isSolid(SurfaceWorld world, Vec3i surfaceBlockInWorld) { + return BlockLogicRegistry.getInstance().get(world.getBlockSfc(surfaceBlockInWorld).getId()).isSolid(RelFace.UP); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java b/src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java new file mode 100644 index 0000000..5ca923a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java @@ -0,0 +1,103 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test; + +import java.util.function.Consumer; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; +import ru.windcorp.progressia.test.gen.surface.SurfaceTopLayerFeature; +import ru.windcorp.progressia.test.gen.surface.SurfaceWorld; + +public class TestTreeFeature extends SurfaceTopLayerFeature { + + public TestTreeFeature(String id) { + super(id); + } + + private void tryToSetLeaves(SurfaceWorld world, Vec3i posSfc, BlockData leaves) { + if (world.getBlockSfc(posSfc).getId().equals("Test:Air")) { + world.setBlockSfc(posSfc, leaves, false); + } + } + + private void iterateSpheroid(Vec3i center, double horDiameter, double vertDiameter, Consumer action) { + VectorUtil.iterateCuboidAround( + center.x, center.y, center.z, + (int) Math.ceil(horDiameter) / 2 * 2 + 5, + (int) Math.ceil(horDiameter) / 2 * 2 + 5, + (int) Math.ceil(vertDiameter) / 2 * 2 + 5, + pos -> { + double sx = (pos.x - center.x) / horDiameter; + double sy = (pos.y - center.y) / horDiameter; + double sz = (pos.z - center.z) / vertDiameter; + + if (sx*sx + sy*sy + sz*sz <= 1) { + action.accept(pos); + } + } + ); + } + + @Override + protected void processTopBlock(SurfaceWorld world, Request request, Vec3i topBlock) { + if (request.getRandom().nextInt(20*20) > 0) return; + + Vec3i start = topBlock.add_(0, 0, 1); + + BlockData log = BlockDataRegistry.getInstance().get("Test:Log"); + BlockData leaves = BlockDataRegistry.getInstance().get("Test:TemporaryLeaves"); + + Vec3i center = start.add_(0); + + int height = request.getRandom().nextInt(3) + 5; + for (; center.z < start.z + height; ++center.z) { + world.setBlockSfc(center, log, false); + } + + double branchHorDistance = 0; + + do { + double branchSize = 0.5 + 1 * request.getRandom().nextDouble(); + double branchHorAngle = 2 * Math.PI * request.getRandom().nextDouble(); + int branchVertOffset = -2 + request.getRandom().nextInt(3); + + Vec3i branchCenter = center.add_( + (int) (Math.sin(branchHorAngle) * branchHorDistance), + (int) (Math.cos(branchHorAngle) * branchHorDistance), + branchVertOffset + ); + + iterateSpheroid(branchCenter, 1.75 * branchSize, 2.5 * branchSize, p -> { + tryToSetLeaves(world, p, leaves); + }); + + branchHorDistance = 1 + 2 * request.getRandom().nextDouble(); + } while (request.getRandom().nextInt(8) > 1); + } + + @Override + protected boolean isSolid(SurfaceWorld world, Vec3i surfaceBlockInWorld) { + return BlockLogicRegistry.getInstance().get(world.getBlockSfc(surfaceBlockInWorld).getId()).isSolid(RelFace.UP); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java index 1f69e00..6c14a2b 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java @@ -26,6 +26,8 @@ import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.test.TestBushFeature; +import ru.windcorp.progressia.test.TestGrassFeature; +import ru.windcorp.progressia.test.TestTreeFeature; import ru.windcorp.progressia.test.gen.surface.Surface; import ru.windcorp.progressia.test.gen.surface.SurfaceFeature; import ru.windcorp.progressia.test.gen.surface.SurfaceFeatureGenerator; @@ -41,6 +43,8 @@ public class PlanetFeatureGenerator { Collection features = new ArrayList<>(); features.add(new TestBushFeature("Test:BushFeature")); + features.add(new TestTreeFeature("Test:TreeFeature")); + features.add(new TestGrassFeature("Test:GrassFeature")); int seaLevel = (int) parent.getPlanet().getRadius(); this.surfaceGenerators = AbsFace.mapToFaces(face -> new SurfaceFeatureGenerator( @@ -59,6 +63,8 @@ public class PlanetFeatureGenerator { } else { generateBorderFeatures(chunk); } + + chunk.setGenerationHint(true); } private boolean isOrdinaryChunk(Vec3i chunkPos) { @@ -72,7 +78,6 @@ public class PlanetFeatureGenerator { private void generateBorderFeatures(ChunkData chunk) { // Do nothing - chunk.setGenerationHint(true); } } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java index 649a6e9..e8307cb 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java @@ -69,6 +69,8 @@ class PlanetTerrainGenerator { } else { generateBorderTerrain(chunk); } + + chunk.setGenerationHint(false); return chunk; } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java index 82f0f55..1dbd5b8 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java @@ -72,7 +72,7 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { @Override protected boolean checkIsChunkReady(Boolean hint) { - return hint == Boolean.TRUE; // Avoid NPE + return Boolean.TRUE.equals(hint); // Avoid NPE } @Override @@ -91,7 +91,6 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { ChunkData chunk = getWorldData().getChunk(chunkPos); if (chunk == null) { - getServer().getLoadManager().getChunkManager().loadChunk(chunkPos); chunk = getWorldData().getChunk(chunkPos); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java index aa0ef6c..69e6d8b 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java @@ -27,36 +27,44 @@ import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.generic.GenericChunks; -import ru.windcorp.progressia.common.world.rels.AxisRotations; public abstract class SurfaceFeature extends Namespaced { public static class Request { + private final SurfaceWorld world; private final ChunkData chunk; private final Vec3i minSfc = new Vec3i(); private final Vec3i maxSfc = new Vec3i(); private final Random random; - public Request(ChunkData chunk, Random random) { + public Request(SurfaceWorld world, ChunkData chunk, Random random) { + this.world = world; this.chunk = chunk; this.random = random; - Vec3i absMin = chunk.getMinBIW(null); - Vec3i absMax = chunk.getMaxBIW(null); + Vec3i tmpMin = chunk.getMinBIW(null); + Vec3i tmpMax = chunk.getMaxBIW(null); + + GenericChunks.relativize(tmpMin, chunk.getUp(), tmpMin); + GenericChunks.relativize(tmpMax, chunk.getUp(), tmpMax); - AxisRotations.relativize(absMin, chunk.getUp(), absMin); - AxisRotations.relativize(absMax, chunk.getUp(), absMax); - - Glm.min(absMin, absMax, minSfc); - Glm.max(absMin, absMax, maxSfc); + Glm.min(tmpMin, tmpMax, minSfc); + Glm.max(tmpMin, tmpMax, maxSfc); + + minSfc.z -= world.getSurface().getSeaLevel(); + maxSfc.z -= world.getSurface().getSeaLevel(); } public ChunkData getChunk() { return chunk; } + public SurfaceWorld getWorld() { + return world; + } + public Random getRandom() { return random; } @@ -93,56 +101,6 @@ public abstract class SurfaceFeature extends Namespaced { return maxSfc; } - public boolean contains(Vec3i surfaceBlockInWorld) { - Vec3i bic = Vectors.grab3i(); - bic.set(surfaceBlockInWorld.x, surfaceBlockInWorld.y, surfaceBlockInWorld.z); - bic.sub(minSfc); - boolean result = GenericChunks.containsBiC(bic); - Vectors.release(bic); - return result; - } - - public void forEach(Consumer action) { - VectorUtil.iterateCuboid( - minSfc.x, - minSfc.y, - minSfc.z, - maxSfc.x + 1, - maxSfc.y + 1, - maxSfc.z + 1, - action - ); - } - - /** - * Provided vectors have z set to {@link #getMinZ()}. - */ - public void forEachOnFloor(Consumer action) { - forEachOnLayer(action, getMinZ()); - } - - /** - * Provided vectors have z set to {@link #getMaxZ()}. - */ - public void forEachOnCeiling(Consumer action) { - forEachOnLayer(action, getMaxZ()); - } - - /** - * Provided vectors have z set to layer. - */ - public void forEachOnLayer(Consumer action, int layer) { - VectorUtil.iterateCuboid( - minSfc.x, - minSfc.y, - layer, - maxSfc.x + 1, - maxSfc.y + 1, - layer + 1, - action - ); - } - } public SurfaceFeature(String id) { @@ -150,5 +108,59 @@ public abstract class SurfaceFeature extends Namespaced { } public abstract void process(SurfaceWorld world, Request request); + + /* + * Utility methods + */ + + public boolean contains(Request request, Vec3i surfaceBlockInWorld) { + Vec3i bic = Vectors.grab3i(); + bic.set(surfaceBlockInWorld.x, surfaceBlockInWorld.y, surfaceBlockInWorld.z); + bic.sub(request.minSfc); + boolean result = GenericChunks.containsBiC(bic); + Vectors.release(bic); + return result; + } + + public void forEach(Request request, Consumer action) { + VectorUtil.iterateCuboid( + request.minSfc.x, + request.minSfc.y, + request.minSfc.z, + request.maxSfc.x + 1, + request.maxSfc.y + 1, + request.maxSfc.z + 1, + action + ); + } + + /** + * Provided vectors have z set to {@link #getMinZ()}. + */ + public void forEachOnFloor(Request request, Consumer action) { + forEachOnLayer(request, action, request.getMinZ()); + } + + /** + * Provided vectors have z set to {@link #getMaxZ()}. + */ + public void forEachOnCeiling(Request request, Consumer action) { + forEachOnLayer(request, action, request.getMaxZ()); + } + + /** + * Provided vectors have z set to layer. + */ + public void forEachOnLayer(Request request, Consumer action, int layer) { + VectorUtil.iterateCuboid( + request.minSfc.x, + request.minSfc.y, + layer, + request.maxSfc.x + 1, + request.maxSfc.y + 1, + layer + 1, + action + ); + } } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java index ade7869..9a3c909 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java @@ -46,7 +46,7 @@ public class SurfaceFeatureGenerator { SurfaceWorld world = new SurfaceWorld(surface, chunk.getWorld()); Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/); - SurfaceFeature.Request request = new SurfaceFeature.Request(chunk, random); + SurfaceFeature.Request request = new SurfaceFeature.Request(world, chunk, random); for (SurfaceFeature feature : features) { feature.process(world, request); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java new file mode 100644 index 0000000..5947950 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java @@ -0,0 +1,58 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen.surface; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.Vectors; + +public abstract class SurfaceTopLayerFeature extends SurfaceFeature { + + public SurfaceTopLayerFeature(String id) { + super(id); + } + + protected abstract void processTopBlock(SurfaceWorld world, Request request, Vec3i topBlock); + + protected abstract boolean isSolid(SurfaceWorld world, Vec3i surfaceBlockInWorld); + + @Override + public void process(SurfaceWorld world, Request request) { + Vec3i cursor = Vectors.grab3i(); + + forEachOnLayer(request, pos -> { + + cursor.set(pos.x, pos.y, pos.z); + + if (!isSolid(world, cursor)) { + return; + } + + for (cursor.z += 1; cursor.z <= request.getMaxZ() + 1; ++cursor.z) { + if (!isSolid(world, cursor)) { + cursor.z -= 1; + processTopBlock(world, request, cursor); + return; + } + } + + }, request.getMinZ()); + + Vectors.release(cursor); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java index 740cc50..12ff59a 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java @@ -31,8 +31,9 @@ import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataReference; import ru.windcorp.progressia.common.world.tile.TileDataStack; -public class SurfaceWorld implements GenericWritableWorld { - +public class SurfaceWorld + implements GenericWritableWorld { + private final Surface surface; private final GenericWritableWorld parent; @@ -61,7 +62,7 @@ public class SurfaceWorld implements GenericWritableWorld getChunks() { return parent.getChunks(); @@ -76,37 +77,50 @@ public class SurfaceWorld implements GenericWritableWorld getEntities() { return parent.getEntities(); } - + @Override public EntityData getEntity(long entityId) { return parent.getEntity(entityId); } - + @Override public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { parent.setBlock(blockInWorld, block, notify); } - + @Override public void addEntity(EntityData entity) { parent.addEntity(entity); } - + @Override public void removeEntity(long entityId) { parent.removeEntity(entityId); } - + public Vec3i resolve(Vec3i surfacePosition, Vec3i output) { if (output == null) { - output = new Vec3i(); + output = new Vec3i(); } - + output.set(surfacePosition.x, surfacePosition.y, surfacePosition.z); + output.z += getSurface().getSeaLevel(); + + GenericChunks.resolve(output, getSurface().getUp(), output); + + return output; + } + + public Vec3i relativize(Vec3i absolutePosition, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + output.set(absolutePosition.x, absolutePosition.y, absolutePosition.z); + + GenericChunks.relativize(output, getSurface().getUp(), output); output.z -= getSurface().getSeaLevel(); - - GenericChunks.resolve(surfacePosition, output, getSurface().getUp()); - + return output; } @@ -117,7 +131,7 @@ public class SurfaceWorld implements GenericWritableWorld zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3>va%8)Xr2lgjwFJ(?ayXjx4tn|hIT@i;-uJ4k z%DV25Qieh&cnHAZ4uHq(|NDQA`H%nj4`*AoCZ`u)?{c>jEV z`TorP{kr-2f#;>b*YN&Y^XK)=>z?=f&+GGZozCm&*M-{t{9ye3gZ{aYub&V2y#D>5 z;NAz=&xK9@TqyX@C&%~q@ovlJR?F{On4kBb&(H5R@W0U?F%+Lub|vy>^tP1T_`Z4@ z3;VXT&@+A0@1^m%&_DiezHjxc$?xET< zlXL$05?f zN=QunXyIgof2V8CW5(m6Tdup~_We5DWQoylU-;_%#JJP&V#OHE&miMQ{p*e|p@oI1 zeVDjI;8p*#7I#0k-H)4u*s{x2gLgPCCeQf)`q%t--gJ%v$~jwq_KJ0RMH;J+<(xCt z@ir{t&Sz88-Qe%P|NKXG4OlSUZLZv4w?kLJ{3E$P&K0hq18+=xeF5ys`dol5Vg-rC zxPS$0b|Ja!Z1LU{=h(=KfjUd~A^L$?TuOeiNFPJU7>6j}v-zFk?puBG?`41xL!^)m z0a>w7$5=5Y{HMf<5A_sMOey75QcW%O9I_%T=aPk}y@V1=D!G(WODo;fP-9Is*HUY3 zwKv}ah?^Sm*lKI7cRsXp<<4(+-q8E-BaArG$fJxp+UV1p8D^Ym=2>Q)ZT96?Sj6$l ztE{@(>f3ExX~&&*-euR_c0ah<2`8R(@+qgDW={XH+Q+Q_^6&q^YVKn-e=VgqmLIF} zYAN4KIKfGh&9In{4ucn2zy;&IY-X#A(aUnOnQfk^NS;L|8D}|J3=78Xd^+yOc7H6F zOvwK`b~6~l|8H2%$aMb=%l)g}{+-oUzlknf3n>h>sWuROys4j%POa%2?@kS8kCn>d zXVI5Fx4x^X2h*3nou}`1^j+EOeyyX|b&_vmrp$}0OzcqnEN3)jQh?2tux4Y8na!?q zcfyMs%6+nby_GY|=(^b0;b5G}-(p(6OpmSmS}UZH=3JPp_L`%`4ki)07=KN7QeUj9 zrc}DH<*ePq;pQBF>NhI;*wS*odwx`p-F=Pa#@S&mqfg$0-`x0-GC<4gti!qjueroM zRevTKH*c)QuY`yx7G_%$!eHy}cSXJJJ@!fXS*|sY6xtX;mrrbmeqp2)@>uxd0G{_u ze&^NmXiBsezl(kLXfhyFhOZ~~U9_QGbh63*G`5d@o74B=`SIi)mSw48?!WBm5)3Kr}8#Z!g22p@K z{IO5&ZuPPqnQ+!#3jUMWc==SvD*=#&Llyj0CaGZU9BuhvVrYHgCf*TAqhqmE;BWK9;1FXO-fL}X5Tu&l}jSP-2g6#%mK#bxD_bl^i<-tD|`*cHe4Co z1wNv(Ms4kmZ)+Xz9B!31$_#sXzlio#c4^=l7*pkxXKqqmUDMQppZ2kQ?j2X05wmi; zv&iF)^ZJCCS$E%&$ZLJqGiN@)?40Z!<{-|A_!PVi4Ijj@6e&e+w2Gvfx_2sj!-;_Nf=V0kMG&LI8@9kw*Ze+kId z3Q$*i$?R5~rf2*J-XC($XVkDqvWv97c5G~Y5`TgOmg+EquUI@b5-Ynya!^DZVII^E zx~BWeY-a)T{MlSSg8_T8BOVD-LD@uHCZSeac&3{tj~6JrUROyA>UVrd6`TPk2#y&u z*2Aw3ur}~)J|TgXs||Y*v`01@m`-`c))OR;eBhlab0^-NmL-Yw3IQZcNg0Fq1(mA} z%a*YUtL7KVh0mc+DTgcz2u3iE#hSHtCAotn>?NScmibY00{_$Wq(9gsS86BA@IW0* zw%uI``{0%b0KR*42qwVW;^(q;+bsbyKDpu9=SW;*gqtY}Tl^BmOk8rE`#Q0*_>5*+ zSwt#s+eTd6b=rhEp$Gu2Op5aOG&%=2f)!&3ejPv{Y$ri^(-Nq%YB0)E?USdpdi)E& zjG!d;DKV~1#JRZY9u8CBHTmeKNvtsL)?A8q0<&h%cnI>q{R#Yf$HKV*w`A>+SqBTj z%SrKmoP3d1e%b`Hd2*X%`nyN?F_;6L@V=}CT8`A_>UU9{Eg~L{-*pujXiY#?X7_Q{ z3nvP$!Ht9FkcfEEhOJUCY&NxHKTtN{P~1`Q`YN!;h@+5)1DpW+oofXQkTIfzAJw?J zGBUS;^~w7M@mOrYAz2W2yUR!~$Dao=9W(3hNaz9C7f}S!Oxpt z;Nl^*HbD!U3YyI{z#}*cZxoG!7{T7fZNBd8aL*+v;`7}RU3xrv;qHgl&Rsa|Dk&TP zVK2NR`O1%PXx2!=y6b2g+~$@9bkKWd8=;+S`swwh=Y^+C zQvMlGbzuyy?evFu90-UX4IvZUAdg|$B{l~1+ISK0+y`h?*ujb8RTkjEF7UBM2! zL?;JGwcuMMc;o{x;6Qu%5qd3g!}jg-k~}C>;T=s2|~;V#^!25G~v9&y<<(V_yns0$vvim zOOx68%G-$i;5JcM@;5LGZ+Y@}WtK)Oc{ zp{2wF;Q<0VTcVMv$tX3f-KJv+v1E+vdrwPz#EFlLA>}q&a$psAjCx#<=XB-Qxd?4Y zs`bFqm&6s}TPI?FRChvI77|iO^Q>n*677TBm{g2ebFUF9y%Rim7PIZTMA#L1$=Sb% zFp`2uQBWKJ@(~;YVgh_v3)y(0s0>P##9`{%8w&4p5-D!!l42MwDg;B#6hcnQFnJ+e z4l#!2y?}E3^&>=f!lm(Sd@F4a@+~5j%kNE)aXmn4llp#0vC<##yqpw9&fMH3#PfM> zFcA2P57z(OYaL2~oJc+wVMR6KZ^+CLCFF;s2TlBG=d&_Z(N8&B$}1{?#s=J|KZe_8EACOrjaLJ3?BUzrLQIuVX2M zTX9{e46iDHzm4Z@UVMlHd&(^yxC4+KNRxi+T7c4c@0$;`t(Z%2{9Z<14l~2ZjYUX& zpyi46qUZtN@DV>T5(r*knh^gg;wC465pv57s3PP+NKnf_lu`zdGq_l{^@Q|*Qez^b z12c*y=pISZD8QIoXXH5GB~kKJd!NR8vyzA*v-XgODTy#z+x`S)i6^+dyKlos{F7 z42YX2Lm)#Zb;mAlnVev_VG{M@WeH2zQ;0*m3Qr;WYbePf))Uyd(LkUgv<9&8kVJB< zCxbcgJQkurS```zMxQDX>%DlJ#L?xjyIRSpk(>nKM)#P_wr~q# z1#N)2ky8>m+9H}HW>ZU&oY!64#~nrzy8 zX%#D~H&ky!)Iu7QpNTN$M_F_djXBSNI>3oZ*~rOj2UN3Dq+?m3g>Ghn{ToINiW6@0 zZcGmuG9F1B>UNMMqAW5yG7F9d$cTZX@<`FesaN81FP7Zysz6!=;cx;r;%|PdfIzZ_ zjkDLvQllF9B}oi)Ya|NMcxV(~#AO$#MY>mQQ&yJWxi?%Vro6wJj+8=!d`WY`vyYX znWREyJ0%u&L%=j58Z|k{x|b#oN?TBA+^pZ;!7jVwoB4N6zttMV$%+I|Y84vHYcTEV zRU6{26;WlEO9pof^R33)^?VPvevTPCp3UYX(Fq+bDn#r~99PH;5*pS52H=|s8Ueyp z(63p1JZY;%?{BSYk!g{^2@+Npp}$F+B;A*Q?B8Td)hd*1DH4BTJC$Xp=UD5O#R`$s4f{ND-sL6cA~q<)q@{#M8Mh)D?!e$lGINaulSe30 z!(9TsN}<6=|gE7q>;SB*Q2^FDGCrEi|`w)Kuux;O`7s(*!#;6@LP!U zzZ9B2b*6$7+ya|GlsKc&Xib=8^0rCDPUX~LPhMJOAkprsdAIp8~!a1h# zD)Q;plMD%L!oi_lgOn*6_-ZmJDj3}j&(rQJs7HxJfQ!{(YVx=x-?GLPPYnz{N9r#SK3fqhh*g$cyNRRNRs!YVN9}y&0^F~s1i;SZVJsxInUaGh7`R2QTp^fUnipWQTSl-ja%kJpFjl{&;pX$!)Zk%}l(sQ){yv=}W z>baEW)xRouqOY%l#&xgq+Y-tkp1v95(NPk|U zkk|Go4P5S{UZO#v#7-Vo$S6gT2ltw%1#z!iVul>RCL{^)E4UJJO$#oP_*>wGd?ES~ zmiz#0(e~Br`B;=q!*QV(B|^tnp8XcwBbtdA3u+$#B7j8OGY@WfnTVcU$zR%gL$V0* z;r+liyW*iNH{m=&r;vD*?p7va>Z%Tt;*zN_ShWe*8avdp6PSGJVqIOop_-stTf5>- z+ytMTCoFW5m4dB=W3jLiHIim)2s9LOfuUec7DkY;5O&pmiZf)f+ip7UC8AFT&j{GW zkD^h226c)G_~`2x@c#t!|G>r|GrHcN@2m?fquxp#9<^~t(kVJ(Y~#E*2tz|Ri^;_F zE?xY+S9U^pNZfWgg|tTuo4=3~k`-=npX2985XzonBSRa&KEUABlL<@c8p##tQP&_S z;2R`FH8KdwpH}McPU;|Sk${j{73Q99{Vc|2!OK@LWEa&NiQb>92XT1;vI@g+87MTN zRJoDBop2-E8jkR9i%j$3qF?z&eE|M~s^RHnJ<{0>Zd*re^LYz(L|`Bb;oHD3zy&ed zRTWj>hN~@=ue0(o`UzR@&zR4@NNwaaJP<-zvpG?}@6mE{UE&G#>p~F00U3)D}R3YR}hXCPKOSAZtN8b$L9X&ibD&W2CJJN0cypo3WT zUPBkI?X1R;Bfj{3yecJ?)CE)GOk8+_nn6?U?5!bDf zYqz^Ze2EF(n!A6%rUAJQymqA6sR7k7lsbtyh19F39nFBCdDe|luEu|*3JJ%2tAvd# z)eVn2xC`SPl{R~IFPH>(8ro3%CJ9q}o)KoqnwIRZpz6c}s&^R+M=Ne$?^WGAzM7so zDv}VW1*jq4j`D8hfU-9X&LuRg-UGxNqBX^`+A5$X3{^yH$2*KAfMO#{yA`OY_WDMm zlHnj1b!fa}LSh8&e7a%VvQ?$7E0j<6@zWogSGKd|FcLYbSCtZ85f;mC8drELd<`WM zhL$CgSene5s;@sja(h{9aJZqGplxwhgu&vifdJ`9M72K zV0@a-AoreOfAZJ56dF>3FgLy;i(t{8@)7u}I?!a|67!sbPfk@#K0*tpe zO#&yC>fxsu75eSIHi-F4`dOIg1-rAy(+p5V%b`{_>tBd4$s!;i7K6d3{0gQ%^Zb+h_P8c0+rOrP!JN0qP#99vVDl; zrmfcR9Skvjs$VK@LB7gCozhRHzjGnvD)tLsmx5Cr5>Jl*t_5sf4|vDOZC5fBi8j_~ z@0iDs(B>-P^>E)*6NzdyiRB61%}xUa7iuTW#0?~`$|$Wvnh~#T6v>3V&%Q%AQGuKH zb!pHGd1|stFN#9LTI8I@I?N1jf`;T0<=H6Cjc!+GS%no}l#A8+xbuA)IgB8#28(id zy;!1fnxVS33b+nn;!~O$kZ^z`4_7~|p}V3OT5})^++bFlT|4o zV%C(QjwXV{`+dI6B(&pacmUoqeKMQfQELXV(XwV{5H_SBLUJwuvGb!_1w~e*quD=F zgS$Cr-I^%C*|1YFDraTUvz!2DOR_*dSR5Z&&X$h{9AqW?h}RH65;ogw9PM@)!S%5; zfpELqP$1N2QnPF3*H?F{3~99Ltw5vJ2}Yt4y-X8PWv6ItMDoRGD#TBX(}0Xb*3qqy zk}ytDTd$GFi}Xo(y<-$gcnW1IZl)-CA#ThDUsEfZ7s*j2JH&F+$dp)zrlp4Fr6Bqm zl(IMJlTAT#buQj0-7UbHN4a|vLDhT&pTF-|!>1L%9c&*O3>#?wbe{Jwao<+5=%HXN zu!kr7heMo8pNBs_Z`>($C_1Z0B5@O zPSP~-HutAu`!lxm5hWvac{^&mo70Ml8QqcyB@Wf0f+RvQWo9T&Wq*=up3l_`=QVy{ zXOCtvl>qAPs+)Ry2N6VbI!XYMB)88Lhxc1VP7}p6L+iNW3@a=EMPs#O4JFkW=?uO+JE{5!3E5I{X)f9oB%kpj9 za%8y*&uXgHX1m4k9H9_6$F}Pba*tcll*w9e#I3@J)b>Z_Q z3ffi^9`itKARoq-P(3_Pw%^ati zxy?urr689#nX0SzEF!C#pTljkS3Mab6yLtUK1l`;r=ffbCQ8%7fPv4DJZuIm^cj~* zL}S8jx(>X!00HgaNvn_gPPdb(!n7MIvKocvsYF=t%Rhwp1Am~v2~yovBgOSqv_vuf zb?nNhTLQ2kuT;f}>oW{2yN0$X<;{2yai8f^dqK|X)EhB_mo;!=3o9nC2I(`Cya$mb1F_wSNYrk5-w1o^#eG)B4t zoHk&6sEv)uY62T7bc0(A%$K6FkwymRKSl=eR|$C%Bpee%MU`ZwH8q?RUNy7rH}8+z zWOq*>JTWZ91yfPnQ@!`2Vrh07Vn)4L@e_7us$o-=MF#RDp!&c|KhUQCxZiiT_g;HP zUELY>(h7eguZzxe_qg_e1?tq3=3f1sdo3whwavnC7jcNNKh=9yX_Cen;~jHu6<89- zMS4MJ3B4_v{3V?o`JwWxjjCw2d+o6nncLknlZ+^Z>t!sXyzh1{F67+8n2{xw^g~pVMZJ_d;0p16k)?jgTOCnsr zh>CG{8WLciiWcv}rE?lhxZ6p}%L2es^d_ z(ss9~kBew98kmus&f(4Y)=vzU`D)DYY|JQJIX{KBtOG58K=2aza?TB?YtleI00Tx$ zcJZF9<5aWaXO2W@7CWdJJCesfmr$Vblxw^2w5rSt<+^h1Lh4pcc}EQZpmmk|d6S>u z5j$98d7n(vIl>S<_?@bVoyqS;5MN~SenGeV_m1_i3fEf1+7 zwwyGxKBHo8+X|haAbsajx37@yaE}z)^?LCZ z8wW+OQS}7N)FR1q?wl}M?o~|O?U_Lw{laOun=b`=`YgRkHT$k9!KR(LBWT+-$fOTdb>oNh^_0&MhFbstg-I?7Us7v2yVTz!U`Vg3(u*-@AZBQ>F>8{~IcWC-axhU<55j>! zHL>D)HNY}w7`;*$!(g>S$1(ZEJt#6*# zmj?Th`z02goPu*z9jsCv_|8bde9#IIKzv?j6f}kN8H`!#Ws|*NWVyFHFBz=*hM>W4 zZRv2<_|8PDNQ$r{MZmrA^QBhKKxeD(S4|$0@= z-oLpR^CqrzoXuir`v$Il=B-pl8yaO5{ir%mqS2r&0z@D-)TN^!wKFJCFSn|{ zCau&lfJv{WsmyP~SRDOows3BXtUYA!-jHH5u9li+VzQ?Abc#<3GD!E|S*w%QNUDc( zgG(nW8tJtE8n&u$YD^l+NkVFx6_YmQImEz1+-rWRtAbwDXn8aQ5~9;SKEG2x5bb_N z&DiPBxrU}OL41-ZZyK@kI`nsJhR5q%QO<=uN*sdT*cq>i&xCw z8rF44OBf1k{Flj|Pbc!Ge#9?~6+c2tk%YWj*{Y#PYAUC%d}VN+Lc>qHL(L7ivT`SY z5Tm+J5L|YyneE=pgVJBDofTY)Do6bDniA>Om1{i^u4QyOWN+(y{PxTC`HO|%a^_23^vgF5F6Z~zv5 zSb}bb7^Q)MG4b{B*~{KaBt{|9WYJ9qD9c3PV4XXX7WBQEW-LAGjNcm!^$@CXyDFd4 zzy9~>-`-UUaNVe&4nt%iuNI=wgV$Rt0uOiKppvF+QBqSyNB+|IvP}nR!AWW^25Ohd z#%}4%_P(>1B>*1;g&q+QBsPX1K&N8%_gG$uKC2@X5nxZ{nm31dncO|=rbZT|_!hg@ zcMJy(;?!(Jjced)B@O(la-7vwhA+oy>aSs{eP@ar_y(H-QLNGvON#xD<2#^`n`F;a zq4Ve3Ey>x~-|LXKKl-6la32+=H5~`Yj`ZMVs$%Lid-ZcXMe(3B9X^5e))^8UTtka5 z@37}RLW8PRHw=zXN>6{LafTZA>C@F!RhRv5_r#SEZxF3W8l2nr438)A``ZIPTfQXu z4NJMRNSY!Vb*nx}@(}6Xfef*LT7*&2jKbp<8`O_;?5tzDApgE&^g4?B>CLngKTXm3 zori*k)?#KF&T23+}`#l+z34=ZNR7i6ZX>QrBCJgM*U`$U3aCs72Y>c}Y= zpEVw;U|rH!8n6M-xrqH%behHm1L${I1eCI95Q`2bBTeKkerqK#jXU&nfX!0GErXzv@@LEt>;hdXKu&Z7Bf>>iHI!lEK zU~}Y<+s>NE2ZI#$D%`&r<>EBZ%*VB4+0~-CEb;`-r&^Nk@s8rGtdSBh&*^lXrsmje zR2{5Fokgzrb9@ftRCS(_biyZ=4r;m;(%ZT8~~5>`E`4yqgvWY=Hi z0PzwHE0VIK9+r}t&JyCMlMEIwI^J{r+}wHR+T$CtB-KB{k@@zd5HwC&HMV6I6duD_ zNO*uZ!{$JWrU7C8XpO6U4{WFo7s}HC^>f~*+_F$0kC}t}=8c5VoP7ZmBa*liX|}_H z0&2bDKPX>t82r(hwB)KzTX#0sX#ieW>x_E$8k5(gY1ip3SO0l917BLZ)@^DY^_0~CZ4;Ux{Yz-vxykm<(<<%(XC3h;>Fd}4xfWndO_hl^VQ|+5 zZNa&?%oM*Q`@?5M=Fy;~nOj&x@~ChW*&5tg)8g-7q@E-NLzmPZK*t-fyBV$Dj0Ul~ zr3JseIrljpnptVmK++umP$$OJ8BrHZYC=0h}Anf_vx{ zK#BNlPg#iFeYqX@h~LFMHEI#=s0GOSIks_&QP4E3=DjNN@Sy~oDS}zvxvHqW>C>{g*3GS zpQ{o5Xr#}xPP0pI-NxnVfV(0gf!S5wAtbt3spCKAbKE)91c3=dPv1zAqS#OQGLFw7 zlkpw)Zt7(se{}pBF0I0ns@*KGFK=&`LPMK+BoFssAP4sm3{p5MBmQ}+Pa_~zYYRbh z>){?S;F>yK&~F+adNpgpJq530u*hnDi3AS0wzGrqaqA?``gkszKBfp1mV(-4A|@Qo zyrJ@xLJA)|%{>mLu{w3BXCK^MBVzi|t+TBJjvBX6wH3k}xH9Db?^*v9V)Zk-ve+ecogh$T5}>UbH8?t7-&TkA^_MZWnJ6biL;cy+dW>E)AZ?du+7(dB5V(E*(5c z(-p(SQT3o09VAPd7DaulqPY5f;*^rlJ1*e<7QbT2&fWQ-_e?DF+PW$#@>wc5wH0t? zlm#iUX;>(|xu>CnR=ghHi6J$Kl?-%FLil1rCUK^sw5&mis&mYmaVT%ZA*!X`bYKVK z$gim?qKV);fWW1ctQM)-8_SO0)xr_SJ8N(O<91KL7#%!vI#_p>&vzhbqZ~d1L7=Ff zxbzu4*E6y3Z%{LQi>dn^^KL)KykVqAe%iVw%oWUFE)Iga4bs^&nT9+oc7F~Htam<) zJh9cX0deN}l^PLSvM1|^LxX0ui~QX2Nb}|+vk1J}qDK+7L>f3RP!R=$s_+N-2Jvql-@Nfr%4Gtj*LW7JQgt0g5zf_&uPe| zu7L_(x6S(ZxivxCorNUD5PlPcgwozFrYRpHs0W3hhK{DbIv$@tLFN1(nlX#H2-k7v1#y6(`~anK@EDP=&c_9AQ5fxHaNKuGIn)r1=2cd z;59}sCR=ZF`U)3ub;Q0%8`4Je-hD{TSv_B0IYN7+Qy%~T00v@9M??Vs0RI60puMM)00009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-^v0uKxyxRo)^0000PbVXQnLvL+uWo~o; zLvm$dbY)~9cWHEJAV*0}P*;Ht7XSbUXGugsR7l4)l>2jBbsa#@=ezgrBm2l}lQc=w z+N2>((>A3qEEE+L7{Ebblma3uBM*_5XL(4i5r$67Oa+1kL{X-KGQ|M}2Gn8f@DN*p zLYe?g+NMeKVw2s?zIX55z4z-69nU{-emQeQYt4@Sdl(%b)#=#+J*$>Vs0}?Go51H* zQ?8_$8MJwM-|O<=zO8!4b^UVn&6nvvKmAwP_3EAa@M|XtM!lq_3!HoLnNrSbg0%)m zVxQ{RdpXqg_g}5sR@CwQp1;VdHOpkzwtfOeog_c^Fm+^}k@r(ng~L4c_g$286)ySy zh5DRJ)(JqVsBtU@k5VjJ72){F5nb`vOr&RZXS9vB&M2yswHO>etbh5;?fT(6e#OuB zZPl4dLN~V6N!6@_CE?7kAUQ`B6!y)3kTD%c+43#f;1F zz=$@(a4b1Zu~X|>D_$XAOyD(59G@nv{Y)KlSaen$dtToGKA4J6XaJ8VK&9dUu>be3NcV!(l9^Pv z7AUP;UijrJf+a-HG%$T8o9+mdGC|OLKR%Rsh@f-lF}jWda7^ z_Yr@`ARGyE(Iw|eq3lqc@G?9+LRHu=I$K73ip~{FaBV&67-~h^!0n?&0_J`qi7nXIAiM)^$ovQ;;*dy5yRz zm&?F^KGL?gj5_$%A?+04`?cr3niQ^lLA^DF8P;bhS3> zh1m~^gu1-sMvK%g58;L^mV`Q_oU`@xa2z8y?vOr_$Agz8XL(7aEDpSRK(}<%W7`h) zQ4jU2lQr3l8n1eB2QOla?XBiVEs=YZmv0hYlrIF}zMLu5yAn2$H$KM${ zy%w~M*S7H+CKqqMP+LIe zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00JpVL_t(Y$JLb0OH^SLhoAS( zojc=vs3Q{vWvC^&X&ua>FP8~Hxi$#tFNhYkiwassxQYtJvPBRsB5)xslC~zIIO?c_ zALHma-0{xmz3+Y7xe0A_?#AEtJ?A|9&Uw#)(=Kt`gl}sFW%@LPE)iwPKxdoq1n?nU zRAEChziF|QUuCp6QCF^3PtbVQQt5nwO9C>xsk)2T<>1p+QKig1M5WB^+7@5#-Z)lU zk96>P&r#i)gK0VtZX%%jk3Hlg0a~fb__j$)EX2(062o^A!ZX0fWKR7~Wr#{YZp9|* z51i$l>PorHM|GU7Bed1*z8&kVa*`u7pyKPc@dmLL|bU8IYe$h5GQu< zviqDUmK4p+2BE0pen*U5p(BN0ZY5V&@&9h}z}H`@{Yn>IZLKV9W{@`QY_2oXf8D!N zF*yEHU2N~fj`)ZuLBY%uYmV`_=e#$^?o}|!N_v6HzRS(9ffkD4mTaC(udC%4( z=G3T?RhyaBEMxI<TeJ;ui?ZDl(|CUr}g=!M%73Q^hhHy2k5{Gomg)eqvZv?F#c- zIc^O;J&2o1t*fCwNdi*x@akpWFQ##E80qU3bvxLe98#_&SgGkG`X31z&_6TSnRugI nEyQfD)^PDdH97WHaa!~j!ua4Ld5*~=00000NkvXXu0mjfkFYs! literal 0 HcmV?d00001 diff --git a/src/test/java/ru/windcorp/progressia/common/world/generic/GenericChunkRotationsTest.java b/src/test/java/ru/windcorp/progressia/common/world/generic/GenericChunkRotationsTest.java new file mode 100644 index 0000000..ef3d4c3 --- /dev/null +++ b/src/test/java/ru/windcorp/progressia/common/world/generic/GenericChunkRotationsTest.java @@ -0,0 +1,83 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic; + +import static org.junit.Assert.fail; +import static ru.windcorp.progressia.common.world.generic.GenericChunks.*; + +import java.util.Random; + +import org.junit.Test; + +import glm.Glm; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.AbsFace; + +public class GenericChunkRotationsTest { + + private static void assertVecEquals(String message, AbsFace up, Vec3i a, Vec3i b) { + if (a == b) { + return; + } + + if (Glm.equals(a, b)) { + return; + } + + fail(String.format("%s. x = (%4d; %4d; %4d), got (%4d; %4d; %4d) (up = %s)", message, a.x, a.y, a.z, b.x, b.y, b.z, up)); + } + + private void check(int x, int y, int z) { + for (AbsFace up : AbsFace.getFaces()) { + + Vec3i veci = new Vec3i(x, y, z); + + assertVecEquals("Vec3i, x != resolve(relativize(x))", up, veci, resolve(relativize(veci, up, null), up, null)); + assertVecEquals("Vec3i, x != relativize(resolve(x))", up, veci, relativize(resolve(veci, up, null), up, null)); + + } + } + + @Test + public void specialCases() { + + for (int x = -1; x <= 1; ++x) { + for (int y = -1; y <= 1; ++y) { + for (int z = -1; z <= 1; ++z) { + check(x, y, z); + } + } + } + + } + + @Test + public void randomValues() { + + final int iterations = 2 << 16; + final long seed = 0; + + Random random = new Random(seed); + + for (int i = 0; i < iterations; ++i) { + check(random.nextInt(200) - 100, random.nextInt(200) - 100, random.nextInt(200) - 100); + } + + } + +} diff --git a/src/test/java/ru/windcorp/progressia/common/world/rels/AxisRotationsTest.java b/src/test/java/ru/windcorp/progressia/common/world/rels/AxisRotationsTest.java new file mode 100644 index 0000000..27d6368 --- /dev/null +++ b/src/test/java/ru/windcorp/progressia/common/world/rels/AxisRotationsTest.java @@ -0,0 +1,100 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.rels; + +import static org.junit.Assert.fail; +import static ru.windcorp.progressia.common.world.rels.AxisRotations.*; + +import java.util.Random; + +import org.junit.Test; + +import glm.Glm; +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; + +public class AxisRotationsTest { + + private static void assertVecEquals(String message, AbsFace up, Vec3i a, Vec3i b) { + if (a == b) { + return; + } + + if (Glm.equals(a, b)) { + return; + } + + fail(String.format("%s. x = (%4d; %4d; %4d), got (%4d; %4d; %4d) (up = %s)", message, a.x, a.y, a.z, b.x, b.y, b.z, up)); + } + + private static void assertVecEquals(String message, AbsFace up, Vec3 a, Vec3 b) { + if (a == b) { + return; + } + + if (b.sub_(a).length() <= 1e-3) { + return; + } + + fail(String.format("%s. x = (%4f; %4f; %4f), got (%4f; %4f; %4f), d = %f (up = %s)", message, a.x, a.y, a.z, b.x, b.y, b.z, b.sub_(a).length(), up)); + } + + private void check(int x, int y, int z) { + for (AbsFace up : AbsFace.getFaces()) { + + Vec3i veci = new Vec3i(x, y, z); + + assertVecEquals("Vec3i, x != resolve(relativize(x))", up, veci, resolve(relativize(veci, up, null), up, null)); + assertVecEquals("Vec3i, x != relativize(resolve(x))", up, veci, relativize(resolve(veci, up, null), up, null)); + + Vec3 vecf = new Vec3(x, y, z); + + assertVecEquals("Vec3, x != resolve(relativize(x))", up, vecf, resolve(relativize(vecf, up, null), up, null)); + assertVecEquals("Vec3, x != relativize(resolve(x))", up, vecf, relativize(resolve(vecf, up, null), up, null)); + + } + } + + @Test + public void specialCases() { + + for (int x = -1; x <= 1; ++x) { + for (int y = -1; y <= 1; ++y) { + for (int z = -1; z <= 1; ++z) { + check(x, y, z); + } + } + } + + } + + @Test + public void randomValues() { + + final int iterations = 2 << 16; + final long seed = 0; + + Random random = new Random(seed); + + for (int i = 0; i < iterations; ++i) { + check(random.nextInt(200) - 100, random.nextInt(200) - 100, random.nextInt(200) - 100); + } + + } + +}