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. + */ +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); + } + + } + +}