Added SurfaceWorld to facilitate surface feature generation

This commit is contained in:
OLEGSHA 2021-04-13 15:18:15 +03:00
parent 20dccf3d12
commit 6fb7e7fc04
Signed by: OLEGSHA
GPG Key ID: E57A4B08D64AFF7A
8 changed files with 426 additions and 29 deletions

View File

@ -244,13 +244,17 @@ public interface GenericChunk<
}
default void forEachBiW(Consumer<? super Vec3i> action) {
int minX = Coordinates.getInWorld(getX(), 0);
int minY = Coordinates.getInWorld(getY(), 0);
int minZ = Coordinates.getInWorld(getZ(), 0);
VectorUtil.iterateCuboid(
Coordinates.getInWorld(getX(), 0),
Coordinates.getInWorld(getY(), 0),
Coordinates.getInWorld(getZ(), 0),
BLOCKS_PER_CHUNK,
BLOCKS_PER_CHUNK,
BLOCKS_PER_CHUNK,
minX,
minY,
minZ,
minX + BLOCKS_PER_CHUNK,
minY + BLOCKS_PER_CHUNK,
minZ + BLOCKS_PER_CHUNK,
action
);
}

View File

@ -0,0 +1,45 @@
/*
* 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 glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.ChunkData;
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.test.gen.surface.SurfaceWorld;
public class TestBushFeature extends SurfaceFeature {
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);
}
}
}

View File

@ -19,40 +19,40 @@ package ru.windcorp.progressia.test.gen.planet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
import java.util.Map;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.test.TestBushFeature;
import ru.windcorp.progressia.test.gen.surface.Surface;
import ru.windcorp.progressia.test.gen.surface.SurfaceFeature;
import ru.windcorp.progressia.test.gen.surface.SurfaceFeatureGenerator;
public class PlanetFeatureGenerator {
private final TestPlanetGenerator parent;
private final SurfaceFeatureGenerator surfaceGenerator;
private final Map<AbsFace, SurfaceFeatureGenerator> surfaceGenerators;
public PlanetFeatureGenerator(TestPlanetGenerator generator) {
this.parent = generator;
Collection<SurfaceFeature> features = new ArrayList<>();
features.add(new SurfaceFeature("Test:GlassFeature") {
@Override
public void process(ChunkData chunk, Random random) {
chunk.setBlockRel(new Vec3i(8, 8, 8), BlockDataRegistry.getInstance().get("Test:Glass"), true);
}
});
features.add(new TestBushFeature("Test:BushFeature"));
this.surfaceGenerator = new SurfaceFeatureGenerator(features);
int seaLevel = (int) parent.getPlanet().getRadius();
this.surfaceGenerators = AbsFace.mapToFaces(face -> new SurfaceFeatureGenerator(
new Surface(face, seaLevel),
features
));
}
public TestPlanetGenerator getGenerator() {
return parent;
}
public void generateFeatures(ChunkData chunk) {
if (isOrdinaryChunk(chunk.getPosition())) {
generateOrdinaryFeatures(chunk);
@ -67,7 +67,7 @@ public class PlanetFeatureGenerator {
}
private void generateOrdinaryFeatures(ChunkData chunk) {
surfaceGenerator.generateFeatures(chunk);
surfaceGenerators.get(chunk.getUp()).generateFeatures(chunk);
}
private void generateBorderFeatures(ChunkData chunk) {

View File

@ -26,7 +26,7 @@ import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.common.world.generic.GenericChunk;
import ru.windcorp.progressia.common.world.generic.GenericChunks;
import ru.windcorp.progressia.test.gen.TerrainLayer;
import ru.windcorp.progressia.test.gen.surface.SurfaceFloatField;
import ru.windcorp.progressia.test.gen.surface.SurfaceTerrainGenerator;
@ -90,7 +90,7 @@ class PlanetTerrainGenerator {
Vec3 biw = new Vec3();
GenericChunk.forEachBiC(bic -> {
GenericChunks.forEachBiC(bic -> {
biw.set(
Coordinates.getInWorld(chunk.getX(), bic.x),

View File

@ -0,0 +1,46 @@
/*
* 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 ru.windcorp.progressia.common.world.rels.AbsFace;
public class Surface {
private final AbsFace up;
private final int seaLevel;
public Surface(AbsFace up, int seaLevel) {
this.up = up;
this.seaLevel = seaLevel;
}
/**
* @return the up
*/
public AbsFace getUp() {
return up;
}
/**
* @return the seaLevel
*/
public int getSeaLevel() {
return seaLevel;
}
}

View File

@ -18,16 +18,137 @@
package ru.windcorp.progressia.test.gen.surface;
import java.util.Random;
import java.util.function.Consumer;
import glm.Glm;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.VectorUtil;
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 ChunkData chunk;
private final Vec3i minSfc = new Vec3i();
private final Vec3i maxSfc = new Vec3i();
private final Random random;
public Request(ChunkData chunk, Random random) {
this.chunk = chunk;
this.random = random;
Vec3i absMin = chunk.getMinBIW(null);
Vec3i absMax = chunk.getMaxBIW(null);
AxisRotations.relativize(absMin, chunk.getUp(), absMin);
AxisRotations.relativize(absMax, chunk.getUp(), absMax);
Glm.min(absMin, absMax, minSfc);
Glm.max(absMin, absMax, maxSfc);
}
public ChunkData getChunk() {
return chunk;
}
public Random getRandom() {
return random;
}
public int getMinX() {
return minSfc.x;
}
public int getMaxX() {
return maxSfc.x;
}
public int getMinY() {
return minSfc.y;
}
public int getMaxY() {
return maxSfc.y;
}
public int getMinZ() {
return minSfc.z;
}
public int getMaxZ() {
return maxSfc.z;
}
public Vec3i getMin() {
return minSfc;
}
public Vec3i getMax() {
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) {
super(id);
}
public abstract void process(ChunkData chunk, Random random);
public abstract void process(SurfaceWorld world, Request request);
}

View File

@ -26,17 +26,30 @@ import ru.windcorp.progressia.common.world.ChunkData;
public class SurfaceFeatureGenerator {
private final Surface surface;
private final Collection<SurfaceFeature> features; // TODO make ordered
public SurfaceFeatureGenerator(Collection<SurfaceFeature> features) {
public SurfaceFeatureGenerator(Surface surface, Collection<SurfaceFeature> features) {
this.surface = surface;
this.features = new ArrayList<>(features);
}
/**
* @return the surface
*/
public Surface getSurface() {
return surface;
}
public void generateFeatures(ChunkData chunk) {
SurfaceWorld world = new SurfaceWorld(surface, chunk.getWorld());
Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/);
SurfaceFeature.Request request = new SurfaceFeature.Request(chunk, random);
for (SurfaceFeature feature : features) {
feature.process(chunk, random);
feature.process(world, request);
}
chunk.setGenerationHint(true);

View File

@ -0,0 +1,168 @@
/*
* 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 java.util.Collection;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.generic.GenericChunks;
import ru.windcorp.progressia.common.world.generic.GenericWritableWorld;
import ru.windcorp.progressia.common.world.rels.BlockFace;
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> {
private final Surface surface;
private final GenericWritableWorld<BlockData, TileData, TileDataStack, TileDataReference, ChunkData, EntityData> parent;
public SurfaceWorld(
Surface surface,
GenericWritableWorld<BlockData, TileData, TileDataStack, TileDataReference, ChunkData, EntityData> parent
) {
this.surface = surface;
this.parent = parent;
}
/**
* @return the surface
*/
public Surface getSurface() {
return surface;
}
/**
* @return the parent
*/
public GenericWritableWorld<BlockData, TileData, TileDataStack, TileDataReference, ChunkData, EntityData> getParent() {
return parent;
}
/*
* Delegate methods
*/
@Override
public Collection<ChunkData> getChunks() {
return parent.getChunks();
}
@Override
public ChunkData getChunk(Vec3i pos) {
return parent.getChunk(pos);
}
@Override
public Collection<EntityData> 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.set(surfacePosition.x, surfacePosition.y, surfacePosition.z);
output.z -= getSurface().getSeaLevel();
GenericChunks.resolve(surfacePosition, output, getSurface().getUp());
return output;
}
public BlockData getBlockSfc(Vec3i surfaceBlockInWorld) {
Vec3i blockInWorld = Vectors.grab3i();
resolve(surfaceBlockInWorld, blockInWorld);
BlockData result = parent.getBlock(blockInWorld);
Vectors.release(blockInWorld);
return result;
}
public void setBlockSfc(Vec3i surfaceBlockInWorld, BlockData block, boolean notify) {
Vec3i blockInWorld = Vectors.grab3i();
resolve(surfaceBlockInWorld, blockInWorld);
parent.setBlock(blockInWorld, block, notify);
Vectors.release(blockInWorld);
}
public TileDataStack getTilesSfc(Vec3i surfaceBlockInWorld, BlockFace face) {
Vec3i blockInWorld = Vectors.grab3i();
resolve(surfaceBlockInWorld, blockInWorld);
TileDataStack result = parent.getTiles(blockInWorld, face);
Vectors.release(blockInWorld);
return result;
}
public TileDataStack getTilesOrNullSfc(Vec3i surfaceBlockInWorld, BlockFace face) {
Vec3i blockInWorld = Vectors.grab3i();
resolve(surfaceBlockInWorld, blockInWorld);
TileDataStack result = parent.getTilesOrNull(blockInWorld, face);
Vectors.release(blockInWorld);
return result;
}
public boolean hasTilesSfc(Vec3i surfaceBlockInWorld, BlockFace face) {
Vec3i blockInWorld = Vectors.grab3i();
resolve(surfaceBlockInWorld, blockInWorld);
boolean result = parent.hasTiles(blockInWorld, face);
Vectors.release(blockInWorld);
return result;
}
public TileData getTileSfc(Vec3i surfaceBlockInWorld, BlockFace face, int layer) {
Vec3i blockInWorld = Vectors.grab3i();
resolve(surfaceBlockInWorld, blockInWorld);
TileData result = parent.getTile(blockInWorld, face, layer);
Vectors.release(blockInWorld);
return result;
}
public boolean isBlockLoadedSfc(Vec3i surfaceBlockInWorld) {
Vec3i blockInWorld = Vectors.grab3i();
resolve(surfaceBlockInWorld, blockInWorld);
boolean result = parent.isBlockLoaded(blockInWorld);
Vectors.release(blockInWorld);
return result;
}
}