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
This commit is contained in:
parent
6fb7e7fc04
commit
e47fb3c4bd
@ -56,6 +56,7 @@ public interface ChunkSet extends Iterable<Vec3i> {
|
|||||||
|
|
||||||
default boolean contains(int x, int y, int z) {
|
default boolean contains(int x, int y, int z) {
|
||||||
Vec3i v = Vectors.grab3i();
|
Vec3i v = Vectors.grab3i();
|
||||||
|
v.set(x, y, z);
|
||||||
boolean result = contains(v);
|
boolean result = contains(v);
|
||||||
Vectors.release(v);
|
Vectors.release(v);
|
||||||
return result;
|
return result;
|
||||||
@ -63,6 +64,7 @@ public interface ChunkSet extends Iterable<Vec3i> {
|
|||||||
|
|
||||||
default boolean add(int x, int y, int z) {
|
default boolean add(int x, int y, int z) {
|
||||||
Vec3i v = Vectors.grab3i();
|
Vec3i v = Vectors.grab3i();
|
||||||
|
v.set(x, y, z);
|
||||||
boolean result = add(v);
|
boolean result = add(v);
|
||||||
Vectors.release(v);
|
Vectors.release(v);
|
||||||
return result;
|
return result;
|
||||||
@ -70,6 +72,7 @@ public interface ChunkSet extends Iterable<Vec3i> {
|
|||||||
|
|
||||||
default boolean remove(int x, int y, int z) {
|
default boolean remove(int x, int y, int z) {
|
||||||
Vec3i v = Vectors.grab3i();
|
Vec3i v = Vectors.grab3i();
|
||||||
|
v.set(x, y, z);
|
||||||
boolean result = remove(v);
|
boolean result = remove(v);
|
||||||
Vectors.release(v);
|
Vectors.release(v);
|
||||||
return result;
|
return result;
|
||||||
|
@ -106,7 +106,11 @@ public interface GenericChunk<
|
|||||||
boolean hasTiles(Vec3i blockInChunk, BlockFace face);
|
boolean hasTiles(Vec3i blockInChunk, BlockFace face);
|
||||||
|
|
||||||
default Vec3i resolve(Vec3i relativeCoords, Vec3i output) {
|
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) {
|
default B getBlockRel(Vec3i relativeBlockInChunk) {
|
||||||
|
@ -29,7 +29,7 @@ import ru.windcorp.progressia.common.world.rels.AxisRotations;
|
|||||||
|
|
||||||
public class GenericChunks {
|
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) {
|
if (output == null) {
|
||||||
output = new Vec3i();
|
output = new Vec3i();
|
||||||
}
|
}
|
||||||
@ -46,6 +46,23 @@ public class GenericChunks {
|
|||||||
return output;
|
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) {
|
private static int getBorderHits(Vec3i blockInChunk) {
|
||||||
int hits = 0;
|
int hits = 0;
|
||||||
|
|
||||||
|
@ -18,28 +18,49 @@
|
|||||||
package ru.windcorp.progressia.test;
|
package ru.windcorp.progressia.test;
|
||||||
|
|
||||||
import glm.vec._3.i.Vec3i;
|
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.BlockData;
|
||||||
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
|
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;
|
import ru.windcorp.progressia.test.gen.surface.SurfaceWorld;
|
||||||
|
|
||||||
public class TestBushFeature extends SurfaceFeature {
|
public class TestBushFeature extends SurfaceTopLayerFeature {
|
||||||
|
|
||||||
public TestBushFeature(String id) {
|
public TestBushFeature(String id) {
|
||||||
super(id);
|
super(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void tryToSetLeaves(SurfaceWorld world, Vec3i posSfc, BlockData leaves) {
|
||||||
public void process(SurfaceWorld world, Request request) {
|
if (world.getBlockSfc(posSfc).getId().equals("Test:Air")) {
|
||||||
BlockData block = BlockDataRegistry.getInstance().get("Test:Log");
|
world.setBlockSfc(posSfc, leaves, false);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -93,8 +93,6 @@ public class TestChunkCodec extends ChunkCodec {
|
|||||||
|
|
||||||
ChunkData chunk = new ChunkData(position, world);
|
ChunkData chunk = new ChunkData(position, world);
|
||||||
|
|
||||||
assert chunk.getUp() == ru.windcorp.progressia.server.ServerState.getInstance().getWorld().getData().getChunk(position).getUp();
|
|
||||||
|
|
||||||
readBlocks(input, blockPalette, chunk);
|
readBlocks(input, blockPalette, chunk);
|
||||||
readTiles(input, tilePalette, chunk);
|
readTiles(input, tilePalette, chunk);
|
||||||
|
|
||||||
|
@ -140,6 +140,9 @@ public class TestContent {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
register(new BlockLogic("Test:Log"));
|
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 BlockData("Test:WoodenPlank"));
|
||||||
register(new BlockRenderOpaqueCube("Test:WoodenPlank", getBlockTexture("WoodenPlank")));
|
register(new BlockRenderOpaqueCube("Test:WoodenPlank", getBlockTexture("WoodenPlank")));
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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<String> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
103
src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java
Normal file
103
src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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<Vec3i> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -26,6 +26,8 @@ import ru.windcorp.progressia.common.util.VectorUtil;
|
|||||||
import ru.windcorp.progressia.common.world.ChunkData;
|
import ru.windcorp.progressia.common.world.ChunkData;
|
||||||
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
||||||
import ru.windcorp.progressia.test.TestBushFeature;
|
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.Surface;
|
||||||
import ru.windcorp.progressia.test.gen.surface.SurfaceFeature;
|
import ru.windcorp.progressia.test.gen.surface.SurfaceFeature;
|
||||||
import ru.windcorp.progressia.test.gen.surface.SurfaceFeatureGenerator;
|
import ru.windcorp.progressia.test.gen.surface.SurfaceFeatureGenerator;
|
||||||
@ -41,6 +43,8 @@ public class PlanetFeatureGenerator {
|
|||||||
|
|
||||||
Collection<SurfaceFeature> features = new ArrayList<>();
|
Collection<SurfaceFeature> features = new ArrayList<>();
|
||||||
features.add(new TestBushFeature("Test:BushFeature"));
|
features.add(new TestBushFeature("Test:BushFeature"));
|
||||||
|
features.add(new TestTreeFeature("Test:TreeFeature"));
|
||||||
|
features.add(new TestGrassFeature("Test:GrassFeature"));
|
||||||
|
|
||||||
int seaLevel = (int) parent.getPlanet().getRadius();
|
int seaLevel = (int) parent.getPlanet().getRadius();
|
||||||
this.surfaceGenerators = AbsFace.mapToFaces(face -> new SurfaceFeatureGenerator(
|
this.surfaceGenerators = AbsFace.mapToFaces(face -> new SurfaceFeatureGenerator(
|
||||||
@ -59,6 +63,8 @@ public class PlanetFeatureGenerator {
|
|||||||
} else {
|
} else {
|
||||||
generateBorderFeatures(chunk);
|
generateBorderFeatures(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunk.setGenerationHint(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isOrdinaryChunk(Vec3i chunkPos) {
|
private boolean isOrdinaryChunk(Vec3i chunkPos) {
|
||||||
@ -72,7 +78,6 @@ public class PlanetFeatureGenerator {
|
|||||||
|
|
||||||
private void generateBorderFeatures(ChunkData chunk) {
|
private void generateBorderFeatures(ChunkData chunk) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
chunk.setGenerationHint(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,8 @@ class PlanetTerrainGenerator {
|
|||||||
} else {
|
} else {
|
||||||
generateBorderTerrain(chunk);
|
generateBorderTerrain(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunk.setGenerationHint(false);
|
||||||
|
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ public class TestPlanetGenerator extends AbstractWorldGenerator<Boolean> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean checkIsChunkReady(Boolean hint) {
|
protected boolean checkIsChunkReady(Boolean hint) {
|
||||||
return hint == Boolean.TRUE; // Avoid NPE
|
return Boolean.TRUE.equals(hint); // Avoid NPE
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -91,7 +91,6 @@ public class TestPlanetGenerator extends AbstractWorldGenerator<Boolean> {
|
|||||||
ChunkData chunk = getWorldData().getChunk(chunkPos);
|
ChunkData chunk = getWorldData().getChunk(chunkPos);
|
||||||
|
|
||||||
if (chunk == null) {
|
if (chunk == null) {
|
||||||
getServer().getLoadManager().getChunkManager().loadChunk(chunkPos);
|
|
||||||
chunk = getWorldData().getChunk(chunkPos);
|
chunk = getWorldData().getChunk(chunkPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,36 +27,44 @@ import ru.windcorp.progressia.common.util.Vectors;
|
|||||||
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||||
import ru.windcorp.progressia.common.world.ChunkData;
|
import ru.windcorp.progressia.common.world.ChunkData;
|
||||||
import ru.windcorp.progressia.common.world.generic.GenericChunks;
|
import ru.windcorp.progressia.common.world.generic.GenericChunks;
|
||||||
import ru.windcorp.progressia.common.world.rels.AxisRotations;
|
|
||||||
|
|
||||||
public abstract class SurfaceFeature extends Namespaced {
|
public abstract class SurfaceFeature extends Namespaced {
|
||||||
|
|
||||||
public static class Request {
|
public static class Request {
|
||||||
|
|
||||||
|
private final SurfaceWorld world;
|
||||||
private final ChunkData chunk;
|
private final ChunkData chunk;
|
||||||
private final Vec3i minSfc = new Vec3i();
|
private final Vec3i minSfc = new Vec3i();
|
||||||
private final Vec3i maxSfc = new Vec3i();
|
private final Vec3i maxSfc = new Vec3i();
|
||||||
|
|
||||||
private final Random random;
|
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.chunk = chunk;
|
||||||
this.random = random;
|
this.random = random;
|
||||||
|
|
||||||
Vec3i absMin = chunk.getMinBIW(null);
|
Vec3i tmpMin = chunk.getMinBIW(null);
|
||||||
Vec3i absMax = chunk.getMaxBIW(null);
|
Vec3i tmpMax = chunk.getMaxBIW(null);
|
||||||
|
|
||||||
|
GenericChunks.relativize(tmpMin, chunk.getUp(), tmpMin);
|
||||||
|
GenericChunks.relativize(tmpMax, chunk.getUp(), tmpMax);
|
||||||
|
|
||||||
AxisRotations.relativize(absMin, chunk.getUp(), absMin);
|
Glm.min(tmpMin, tmpMax, minSfc);
|
||||||
AxisRotations.relativize(absMax, chunk.getUp(), absMax);
|
Glm.max(tmpMin, tmpMax, maxSfc);
|
||||||
|
|
||||||
Glm.min(absMin, absMax, minSfc);
|
minSfc.z -= world.getSurface().getSeaLevel();
|
||||||
Glm.max(absMin, absMax, maxSfc);
|
maxSfc.z -= world.getSurface().getSeaLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChunkData getChunk() {
|
public ChunkData getChunk() {
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SurfaceWorld getWorld() {
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
public Random getRandom() {
|
public Random getRandom() {
|
||||||
return random;
|
return random;
|
||||||
}
|
}
|
||||||
@ -93,56 +101,6 @@ public abstract class SurfaceFeature extends Namespaced {
|
|||||||
return maxSfc;
|
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<? super Vec3i> 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<? super Vec3i> action) {
|
|
||||||
forEachOnLayer(action, getMinZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provided vectors have z set to {@link #getMaxZ()}.
|
|
||||||
*/
|
|
||||||
public void forEachOnCeiling(Consumer<? super Vec3i> action) {
|
|
||||||
forEachOnLayer(action, getMaxZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provided vectors have z set to layer.
|
|
||||||
*/
|
|
||||||
public void forEachOnLayer(Consumer<? super Vec3i> action, int layer) {
|
|
||||||
VectorUtil.iterateCuboid(
|
|
||||||
minSfc.x,
|
|
||||||
minSfc.y,
|
|
||||||
layer,
|
|
||||||
maxSfc.x + 1,
|
|
||||||
maxSfc.y + 1,
|
|
||||||
layer + 1,
|
|
||||||
action
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SurfaceFeature(String id) {
|
public SurfaceFeature(String id) {
|
||||||
@ -150,5 +108,59 @@ public abstract class SurfaceFeature extends Namespaced {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract void process(SurfaceWorld world, Request request);
|
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<? super Vec3i> 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<? super Vec3i> action) {
|
||||||
|
forEachOnLayer(request, action, request.getMinZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provided vectors have z set to {@link #getMaxZ()}.
|
||||||
|
*/
|
||||||
|
public void forEachOnCeiling(Request request, Consumer<? super Vec3i> action) {
|
||||||
|
forEachOnLayer(request, action, request.getMaxZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provided vectors have z set to layer.
|
||||||
|
*/
|
||||||
|
public void forEachOnLayer(Request request, Consumer<? super Vec3i> action, int layer) {
|
||||||
|
VectorUtil.iterateCuboid(
|
||||||
|
request.minSfc.x,
|
||||||
|
request.minSfc.y,
|
||||||
|
layer,
|
||||||
|
request.maxSfc.x + 1,
|
||||||
|
request.maxSfc.y + 1,
|
||||||
|
layer + 1,
|
||||||
|
action
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ public class SurfaceFeatureGenerator {
|
|||||||
SurfaceWorld world = new SurfaceWorld(surface, chunk.getWorld());
|
SurfaceWorld world = new SurfaceWorld(surface, chunk.getWorld());
|
||||||
|
|
||||||
Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/);
|
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) {
|
for (SurfaceFeature feature : features) {
|
||||||
feature.process(world, request);
|
feature.process(world, request);
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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.TileDataReference;
|
||||||
import ru.windcorp.progressia.common.world.tile.TileDataStack;
|
import ru.windcorp.progressia.common.world.tile.TileDataStack;
|
||||||
|
|
||||||
public class SurfaceWorld implements GenericWritableWorld<BlockData, TileData, TileDataStack, TileDataReference, ChunkData, EntityData> {
|
public class SurfaceWorld
|
||||||
|
implements GenericWritableWorld<BlockData, TileData, TileDataStack, TileDataReference, ChunkData, EntityData> {
|
||||||
|
|
||||||
private final Surface surface;
|
private final Surface surface;
|
||||||
private final GenericWritableWorld<BlockData, TileData, TileDataStack, TileDataReference, ChunkData, EntityData> parent;
|
private final GenericWritableWorld<BlockData, TileData, TileDataStack, TileDataReference, ChunkData, EntityData> parent;
|
||||||
|
|
||||||
@ -61,7 +62,7 @@ public class SurfaceWorld implements GenericWritableWorld<BlockData, TileData, T
|
|||||||
/*
|
/*
|
||||||
* Delegate methods
|
* Delegate methods
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ChunkData> getChunks() {
|
public Collection<ChunkData> getChunks() {
|
||||||
return parent.getChunks();
|
return parent.getChunks();
|
||||||
@ -76,37 +77,50 @@ public class SurfaceWorld implements GenericWritableWorld<BlockData, TileData, T
|
|||||||
public Collection<EntityData> getEntities() {
|
public Collection<EntityData> getEntities() {
|
||||||
return parent.getEntities();
|
return parent.getEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityData getEntity(long entityId) {
|
public EntityData getEntity(long entityId) {
|
||||||
return parent.getEntity(entityId);
|
return parent.getEntity(entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) {
|
public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) {
|
||||||
parent.setBlock(blockInWorld, block, notify);
|
parent.setBlock(blockInWorld, block, notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addEntity(EntityData entity) {
|
public void addEntity(EntityData entity) {
|
||||||
parent.addEntity(entity);
|
parent.addEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeEntity(long entityId) {
|
public void removeEntity(long entityId) {
|
||||||
parent.removeEntity(entityId);
|
parent.removeEntity(entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3i resolve(Vec3i surfacePosition, Vec3i output) {
|
public Vec3i resolve(Vec3i surfacePosition, Vec3i output) {
|
||||||
if (output == null) {
|
if (output == null) {
|
||||||
output = new Vec3i();
|
output = new Vec3i();
|
||||||
}
|
}
|
||||||
|
|
||||||
output.set(surfacePosition.x, surfacePosition.y, surfacePosition.z);
|
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();
|
output.z -= getSurface().getSeaLevel();
|
||||||
|
|
||||||
GenericChunks.resolve(surfacePosition, output, getSurface().getUp());
|
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +131,7 @@ public class SurfaceWorld implements GenericWritableWorld<BlockData, TileData, T
|
|||||||
Vectors.release(blockInWorld);
|
Vectors.release(blockInWorld);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBlockSfc(Vec3i surfaceBlockInWorld, BlockData block, boolean notify) {
|
public void setBlockSfc(Vec3i surfaceBlockInWorld, BlockData block, boolean notify) {
|
||||||
Vec3i blockInWorld = Vectors.grab3i();
|
Vec3i blockInWorld = Vectors.grab3i();
|
||||||
resolve(surfaceBlockInWorld, blockInWorld);
|
resolve(surfaceBlockInWorld, blockInWorld);
|
||||||
@ -140,7 +154,7 @@ public class SurfaceWorld implements GenericWritableWorld<BlockData, TileData, T
|
|||||||
Vectors.release(blockInWorld);
|
Vectors.release(blockInWorld);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasTilesSfc(Vec3i surfaceBlockInWorld, BlockFace face) {
|
public boolean hasTilesSfc(Vec3i surfaceBlockInWorld, BlockFace face) {
|
||||||
Vec3i blockInWorld = Vectors.grab3i();
|
Vec3i blockInWorld = Vectors.grab3i();
|
||||||
resolve(surfaceBlockInWorld, blockInWorld);
|
resolve(surfaceBlockInWorld, blockInWorld);
|
||||||
@ -148,7 +162,7 @@ public class SurfaceWorld implements GenericWritableWorld<BlockData, TileData, T
|
|||||||
Vectors.release(blockInWorld);
|
Vectors.release(blockInWorld);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TileData getTileSfc(Vec3i surfaceBlockInWorld, BlockFace face, int layer) {
|
public TileData getTileSfc(Vec3i surfaceBlockInWorld, BlockFace face, int layer) {
|
||||||
Vec3i blockInWorld = Vectors.grab3i();
|
Vec3i blockInWorld = Vectors.grab3i();
|
||||||
resolve(surfaceBlockInWorld, blockInWorld);
|
resolve(surfaceBlockInWorld, blockInWorld);
|
||||||
@ -156,7 +170,7 @@ public class SurfaceWorld implements GenericWritableWorld<BlockData, TileData, T
|
|||||||
Vectors.release(blockInWorld);
|
Vectors.release(blockInWorld);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBlockLoadedSfc(Vec3i surfaceBlockInWorld) {
|
public boolean isBlockLoadedSfc(Vec3i surfaceBlockInWorld) {
|
||||||
Vec3i blockInWorld = Vectors.grab3i();
|
Vec3i blockInWorld = Vectors.grab3i();
|
||||||
resolve(surfaceBlockInWorld, blockInWorld);
|
resolve(surfaceBlockInWorld, blockInWorld);
|
||||||
|
BIN
src/main/resources/assets/textures/blocks/TemporaryLeaves.png
Normal file
BIN
src/main/resources/assets/textures/blocks/TemporaryLeaves.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
src/main/resources/assets/textures/items/MoonTypeIceCream.png
Normal file
BIN
src/main/resources/assets/textures/items/MoonTypeIceCream.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 705 B |
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user