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) {
|
||||
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<Vec3i> {
|
||||
|
||||
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<Vec3i> {
|
||||
|
||||
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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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")));
|
||||
|
@ -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.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<SurfaceFeature> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -70,6 +70,8 @@ class PlanetTerrainGenerator {
|
||||
generateBorderTerrain(chunk);
|
||||
}
|
||||
|
||||
chunk.setGenerationHint(false);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ public class TestPlanetGenerator extends AbstractWorldGenerator<Boolean> {
|
||||
|
||||
@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<Boolean> {
|
||||
ChunkData chunk = getWorldData().getChunk(chunkPos);
|
||||
|
||||
if (chunk == null) {
|
||||
getServer().getLoadManager().getChunkManager().loadChunk(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.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);
|
||||
|
||||
AxisRotations.relativize(absMin, chunk.getUp(), absMin);
|
||||
AxisRotations.relativize(absMax, chunk.getUp(), absMax);
|
||||
GenericChunks.relativize(tmpMin, chunk.getUp(), tmpMin);
|
||||
GenericChunks.relativize(tmpMax, chunk.getUp(), tmpMax);
|
||||
|
||||
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<? 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) {
|
||||
@ -151,4 +109,58 @@ 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<? 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());
|
||||
|
||||
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);
|
||||
|
@ -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,7 +31,8 @@ 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<BlockData, TileData, TileDataStack, TileDataReference, ChunkData, EntityData> {
|
||||
public class SurfaceWorld
|
||||
implements GenericWritableWorld<BlockData, TileData, TileDataStack, TileDataReference, ChunkData, EntityData> {
|
||||
|
||||
private final Surface surface;
|
||||
private final GenericWritableWorld<BlockData, TileData, TileDataStack, TileDataReference, ChunkData, EntityData> parent;
|
||||
@ -99,13 +100,26 @@ public class SurfaceWorld implements GenericWritableWorld<BlockData, TileData, T
|
||||
|
||||
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();
|
||||
output.z += getSurface().getSeaLevel();
|
||||
|
||||
GenericChunks.resolve(surfacePosition, output, getSurface().getUp());
|
||||
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();
|
||||
|
||||
return output;
|
||||
}
|
||||
|
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