Replaced AbsFace with RelFace or BlockFace where appropriate

- Added BlockFace - a *Face superclass
- Refactored and optimized Rel{Relation, Face}
- Replaced most AbsFace references with BlockFace or RelFace
- Chunks now have an up direction
  - Determined by GravityModel's discrete up
  - Static; cannot change unless chunk is reloaded
  - Chunk models are now rendered rotated accordingly
- Fixed some minor bugs that were somehow revealed by these changes
- Moved TileLogicGrass to .test, where it belongs
- Disabled grass despawn until a new worldgen is implemented
This commit is contained in:
2021-02-07 00:45:43 +03:00
parent 10d271059c
commit d3c5011063
45 changed files with 781 additions and 368 deletions

View File

@ -32,6 +32,8 @@ import ru.windcorp.progressia.client.world.tile.TileRenderStack;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.generic.GenericChunk;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.BlockFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.tile.TileDataStack;
public class ChunkRender
@ -56,6 +58,11 @@ public class ChunkRender
return getData().getPosition();
}
@Override
public AbsFace getUp() {
return getData().getUp();
}
@Override
public BlockRender getBlock(Vec3i posInChunk) {
return BlockRenderRegistry.getInstance().get(
@ -64,12 +71,12 @@ public class ChunkRender
}
@Override
public TileRenderStack getTiles(Vec3i blockInChunk, AbsFace face) {
public TileRenderStack getTiles(Vec3i blockInChunk, BlockFace face) {
return getTileStackWrapper(getData().getTiles(blockInChunk, face));
}
@Override
public boolean hasTiles(Vec3i blockInChunk, AbsFace face) {
public boolean hasTiles(Vec3i blockInChunk, BlockFace face) {
return getData().hasTiles(blockInChunk, face);
}
@ -119,7 +126,7 @@ public class ChunkRender
}
@Override
public AbsFace getFace() {
public RelFace getFace() {
return parent.getFace();
}

View File

@ -36,7 +36,8 @@ import ru.windcorp.progressia.client.world.tile.TileRender;
import ru.windcorp.progressia.client.world.tile.TileRenderNone;
import ru.windcorp.progressia.client.world.tile.TileRenderStack;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.rels.RelRelation;
public class ChunkRenderModel implements Renderable {
@ -53,11 +54,15 @@ public class ChunkRenderModel implements Renderable {
public void render(ShapeRenderHelper renderer) {
if (model == null) return;
float offset = ChunkData.BLOCKS_PER_CHUNK / 2 - 0.5f;
renderer.pushTransform().translate(
chunk.getX() * ChunkData.BLOCKS_PER_CHUNK,
chunk.getY() * ChunkData.BLOCKS_PER_CHUNK,
chunk.getZ() * ChunkData.BLOCKS_PER_CHUNK
);
).translate(offset, offset, offset)
.mul(RelRelation.getResolutionMatrix4(chunk.getUp()))
.translate(-offset, -offset, -offset);
model.render(renderer);
@ -71,8 +76,8 @@ public class ChunkRenderModel implements Renderable {
optimizers.forEach(ChunkRenderOptimizer::startRender);
chunk.forEachBiC(blockInChunk -> {
processBlockAndTiles(blockInChunk, sink);
chunk.forEachBiC(relBlockInChunk -> {
processBlockAndTiles(relBlockInChunk, sink);
});
for (ChunkRenderOptimizer optimizer : optimizers) {
@ -96,16 +101,16 @@ public class ChunkRenderModel implements Renderable {
}
}
private void processBlockAndTiles(Vec3i blockInChunk, Builder sink) {
processBlock(blockInChunk, sink);
private void processBlockAndTiles(Vec3i relBlockInChunk, Builder sink) {
processBlock(relBlockInChunk, sink);
for (AbsFace face : AbsFace.getFaces()) {
processTileStack(blockInChunk, face, sink);
for (RelFace face : RelFace.getFaces()) {
processTileStack(relBlockInChunk, face, sink);
}
}
private void processBlock(Vec3i blockInChunk, Builder sink) {
BlockRender block = chunk.getBlock(blockInChunk);
private void processBlock(Vec3i relBlockInChunk, Builder sink) {
BlockRender block = chunk.getBlockRel(relBlockInChunk);
if (block instanceof BlockRenderNone) {
return;
@ -113,48 +118,48 @@ public class ChunkRenderModel implements Renderable {
if (block.needsOwnRenderable()) {
sink.addPart(
block.createRenderable(chunk.getData(), blockInChunk),
new Mat4().identity().translate(blockInChunk.x, blockInChunk.y, blockInChunk.z)
block.createRenderable(chunk.getData(), relBlockInChunk),
new Mat4().identity().translate(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z)
);
}
processBlockWithCROs(block, blockInChunk);
processBlockWithCROs(block, relBlockInChunk);
}
private void processBlockWithCROs(BlockRender block, Vec3i blockInChunk) {
private void processBlockWithCROs(BlockRender block, Vec3i relBlockInChunk) {
for (ChunkRenderOptimizer optimizer : optimizers) {
optimizer.addBlock(block, blockInChunk);
optimizer.addBlock(block, relBlockInChunk);
}
}
private void processTileStack(Vec3i blockInChunk, AbsFace face, Builder sink) {
TileRenderStack trs = chunk.getTilesOrNull(blockInChunk, face);
private void processTileStack(Vec3i relBlockInChunk, RelFace face, Builder sink) {
TileRenderStack trs = chunk.getTilesOrNullRel(relBlockInChunk, face);
if (trs == null || trs.isEmpty()) {
return;
}
trs.forEach(tile -> processTile(tile, blockInChunk, face, sink));
trs.forEach(tile -> processTile(tile, relBlockInChunk, face, sink));
}
private void processTile(TileRender tile, Vec3i blockInChunk, AbsFace face, Builder sink) {
private void processTile(TileRender tile, Vec3i relBlockInChunk, RelFace face, Builder sink) {
if (tile instanceof TileRenderNone) {
return;
}
if (tile.needsOwnRenderable()) {
sink.addPart(
tile.createRenderable(chunk.getData(), blockInChunk, face),
new Mat4().identity().translate(blockInChunk.x, blockInChunk.y, blockInChunk.z)
tile.createRenderable(chunk.getData(), relBlockInChunk, face),
new Mat4().identity().translate(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z)
);
}
processTileWithCROs(tile, blockInChunk, face);
processTileWithCROs(tile, relBlockInChunk, face);
}
private void processTileWithCROs(TileRender tile, Vec3i blockInChunk, AbsFace face) {
private void processTileWithCROs(TileRender tile, Vec3i relBlockInChunk, RelFace face) {
for (ChunkRenderOptimizer optimizer : optimizers) {
optimizer.addTile(tile, blockInChunk, face);
optimizer.addTile(tile, relBlockInChunk, face);
}
}

View File

@ -23,6 +23,7 @@ import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.ChunkDataListener;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.tile.TileData;
class ChunkUpdateListener implements ChunkDataListener {
@ -57,7 +58,7 @@ class ChunkUpdateListener implements ChunkDataListener {
public void onChunkTilesChanged(
ChunkData chunk,
Vec3i blockInChunk,
AbsFace face,
RelFace face,
TileData tile,
boolean wasAdded
) {

View File

@ -18,7 +18,6 @@
package ru.windcorp.progressia.client.world.block;
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.generic.GenericBlock;
@ -31,13 +30,7 @@ public abstract class BlockRender extends Namespaced implements GenericBlock {
super(id);
}
public void render(ShapeRenderHelper renderer) {
throw new UnsupportedOperationException(
"BlockRender.render() not implemented in " + this
);
}
public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk) {
public Renderable createRenderable(ChunkData chunk, Vec3i relBlockInChunk) {
return null;
}

View File

@ -19,27 +19,27 @@
package ru.windcorp.progressia.client.world.block;
import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public class BlockRenderOpaqueCube extends BlockRenderTexturedCube {
public BlockRenderOpaqueCube(
String id,
Texture posZTexture,
Texture negZTexture,
Texture posXTexture,
Texture negXTexture,
Texture negYTexture,
Texture posYTexture
Texture topTexture,
Texture bottomTexture,
Texture northTexture,
Texture southTexture,
Texture westTexture,
Texture eastTexture
) {
super(
id,
posZTexture,
negZTexture,
posXTexture,
negXTexture,
negYTexture,
posYTexture
topTexture,
bottomTexture,
northTexture,
southTexture,
westTexture,
eastTexture
);
}
@ -55,8 +55,20 @@ public class BlockRenderOpaqueCube extends BlockRenderTexturedCube {
);
}
public BlockRenderOpaqueCube(String id, Texture topTexture, Texture bottomTexture, Texture sideTexture) {
this(
id,
topTexture,
bottomTexture,
sideTexture,
sideTexture,
sideTexture,
sideTexture
);
}
@Override
public boolean isOpaque(AbsFace face) {
public boolean isOpaque(RelFace face) {
return true;
}

View File

@ -20,7 +20,6 @@ package ru.windcorp.progressia.client.world.block;
import static ru.windcorp.progressia.common.world.rels.AbsFace.*;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
@ -39,43 +38,38 @@ import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface.Block
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public abstract class BlockRenderTexturedCube
extends BlockRender
implements BlockOptimizedSurface {
private final Map<AbsFace, Texture> textures = new HashMap<>();
private final Map<RelFace, Texture> textures;
public BlockRenderTexturedCube(
String id,
Texture posZTexture,
Texture negZTexture,
Texture posXTexture,
Texture negXTexture,
Texture negYTexture,
Texture posYTexture
Texture topTexture,
Texture bottomTexture,
Texture northTexture,
Texture southTexture,
Texture westTexture,
Texture eastTexture
) {
super(id);
textures.put(POS_Z, posZTexture);
textures.put(NEG_Z, negZTexture);
textures.put(POS_X, posXTexture);
textures.put(NEG_X, negXTexture);
textures.put(NEG_Y, negYTexture);
textures.put(POS_Y, posYTexture);
this.textures = RelFace.mapToFaces(topTexture, bottomTexture, northTexture, southTexture, westTexture, eastTexture);
}
public Texture getTexture(AbsFace blockFace) {
public Texture getTexture(RelFace blockFace) {
return textures.get(blockFace);
}
public Vec4 getColorMultiplier(AbsFace blockFace) {
public Vec4 getColorMultiplier(RelFace blockFace) {
return Colors.WHITE;
}
@Override
public final void getShapeParts(
ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace,
ChunkData chunk, Vec3i blockInChunk, RelFace blockFace,
boolean inner,
Consumer<ShapePart> output,
Vec3 offset
@ -84,7 +78,7 @@ public abstract class BlockRenderTexturedCube
}
private ShapePart createFace(
ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace,
ChunkData chunk, Vec3i blockInChunk, RelFace blockFace,
boolean inner,
Vec3 offset
) {
@ -93,7 +87,7 @@ public abstract class BlockRenderTexturedCube
getTexture(blockFace),
getColorMultiplier(blockFace),
offset,
blockFace,
blockFace.resolve(AbsFace.POS_Z),
inner
);
}
@ -105,12 +99,12 @@ public abstract class BlockRenderTexturedCube
ShapePart[] faces = new ShapePart[BLOCK_FACE_COUNT + (opaque ? BLOCK_FACE_COUNT : 0)];
for (int i = 0; i < BLOCK_FACE_COUNT; ++i) {
faces[i] = createFace(chunk, blockInChunk, AbsFace.getFaces().get(i), false, Vectors.ZERO_3);
faces[i] = createFace(chunk, blockInChunk, RelFace.getFaces().get(i), false, Vectors.ZERO_3);
}
if (!opaque) {
for (int i = 0; i < BLOCK_FACE_COUNT; ++i) {
faces[i + BLOCK_FACE_COUNT] = createFace(chunk, blockInChunk, AbsFace.getFaces().get(i), true, Vectors.ZERO_3);
faces[i + BLOCK_FACE_COUNT] = createFace(chunk, blockInChunk, RelFace.getFaces().get(i), true, Vectors.ZERO_3);
}
}

View File

@ -19,27 +19,27 @@
package ru.windcorp.progressia.client.world.block;
import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public class BlockRenderTransparentCube extends BlockRenderTexturedCube {
public BlockRenderTransparentCube(
String id,
Texture posZTexture,
Texture negZTexture,
Texture posXTexture,
Texture negXTexture,
Texture negYTexture,
Texture posYTexture
Texture topTexture,
Texture bottomTexture,
Texture northTexture,
Texture southTexture,
Texture westTexture,
Texture eastTexture
) {
super(
id,
posZTexture,
negZTexture,
posXTexture,
negXTexture,
negYTexture,
posYTexture
topTexture,
bottomTexture,
northTexture,
southTexture,
westTexture,
eastTexture
);
}
@ -55,8 +55,20 @@ public class BlockRenderTransparentCube extends BlockRenderTexturedCube {
);
}
public BlockRenderTransparentCube(String id, Texture topTexture, Texture bottomTexture, Texture sideTexture) {
this(
id,
topTexture,
bottomTexture,
sideTexture,
sideTexture,
sideTexture,
sideTexture
);
}
@Override
public boolean isOpaque(AbsFace face) {
public boolean isOpaque(RelFace face) {
return false;
}

View File

@ -24,7 +24,7 @@ import ru.windcorp.progressia.client.world.ChunkRender;
import ru.windcorp.progressia.client.world.block.BlockRender;
import ru.windcorp.progressia.client.world.tile.TileRender;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
/**
* Chunk render optimizer (CRO) is an object that produces optimized models for
@ -35,6 +35,12 @@ import ru.windcorp.progressia.common.world.rels.AbsFace;
* tiles. An example of a CRO is {@link ChunkRenderOptimizerSurface}: it removes
* block surfaces and tiles that it knows cannot be seen, thus significantly
* reducing total polygon count.
* <p>
* As with everything related to rendering chunks, CROs are interacted with
* using the relative local chunk coordinate system. In this coordinate system,
* the coordinates are the chunk coordinates relativized using the chunks's up
* direction. In simpler terms, coordinates are {@code [0; BLOCKS_PER_CHUNK)}
* and Z is always up.
* <h3>CRO lifecycle</h3>
* A CRO instance is created by {@link ChunkRenderOptimizerRegistry}. It may
* then be used to work on multiple chunks sequentially. Each chunk is processed
@ -44,7 +50,7 @@ import ru.windcorp.progressia.common.world.rels.AbsFace;
* instance.</li>
* <li>{@link #startRender()} is invoked. The CRO must reset its state.</li>
* <li>{@link #addBlock(BlockRender, Vec3i)} and
* {@link #addTile(TileRender, Vec3i, AbsFace)} are invoked for each block and
* {@link #addTile(TileRender, Vec3i, RelFace)} are invoked for each block and
* tile that this CRO should optimize. {@code addTile} specifies tiles in order
* of ascension within a tile stack.</li>
* <li>{@link #endRender()} is invoked. The CRO may perform any pending
@ -98,12 +104,13 @@ public abstract class ChunkRenderOptimizer extends Namespaced {
* method is only invoked once per block. This method is not necessarily
* invoked for each block.
*
* @param block a {@link BlockRender} instance describing the block.
* @param block a {@link BlockRender} instance describing the
* block.
* It corresponds to
* {@code getChunk().getBlock(blockInChunk)}.
* @param blockInChunk the position of the block
* @param relBlockInChunk the relative position of the block
*/
public abstract void addBlock(BlockRender block, Vec3i blockInChunk);
public abstract void addBlock(BlockRender block, Vec3i relBlockInChunk);
/**
* Requests that this CRO processes the provided tile. This method may only
@ -113,10 +120,11 @@ public abstract class ChunkRenderOptimizer extends Namespaced {
* this method is invoked for lower tiles first.
*
* @param tile a {@link BlockRender} instance describing the tile
* @param blockInChunk the position of the block that the tile belongs to
* @param relBlockInChunk the relative position of the block that the tile
* belongs to
* @param blockFace the face that the tile belongs to
*/
public abstract void addTile(TileRender tile, Vec3i blockInChunk, AbsFace blockFace);
public abstract void addTile(TileRender tile, Vec3i relBlockInChunk, RelFace blockFace);
/**
* Requests that the CRO assembles and outputs its model. This method may

View File

@ -38,7 +38,7 @@ import ru.windcorp.progressia.client.world.block.BlockRender;
import ru.windcorp.progressia.client.world.tile.TileRender;
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
@ -57,19 +57,22 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
* coordinate system.
*
* @param chunk the chunk that contains the requested face
* @param blockInChunk the block in chunk
* @param relBlockInChunk the relative block in chunk
* @param blockFace the requested face
* @param inner whether this face should be visible from inside
* @param inner whether this face should be visible from
* inside
* ({@code true}) or outside ({@code false})
* @param output a consumer that the created shape parts must be
* @param output a consumer that the created shape parts must
* be
* given to
* @param offset an additional offset that must be applied to all
* @param offset an additional offset that must be applied to
* all
* vertices
*/
void getShapeParts(
ChunkData chunk,
Vec3i blockInChunk,
AbsFace blockFace,
Vec3i relBlockInChunk,
RelFace blockFace,
boolean inner,
Consumer<ShapePart> output,
Vec3 offset /* kostyl 156% */
@ -77,14 +80,14 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
/**
* Returns the opacity of the surface identified by the provided
* {@link AbsFace}.
* {@link RelFace}.
* Opaque surfaces prevent surfaces behind them from being included in
* chunk models.
*
* @param blockFace the face to query
* @return {@code true} iff the surface is opaque.
*/
boolean isOpaque(AbsFace blockFace);
boolean isOpaque(RelFace blockFace);
}
/**
@ -159,29 +162,29 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
}
@Override
public void addBlock(BlockRender block, Vec3i pos) {
public void addBlock(BlockRender block, Vec3i relBlockInChunk) {
if (!(block instanceof BlockOptimizedSurface))
return;
BlockOptimizedSurface bos = (BlockOptimizedSurface) block;
addBlock(pos, bos);
addBlock(relBlockInChunk, bos);
}
@Override
public void addTile(TileRender tile, Vec3i pos, AbsFace face) {
public void addTile(TileRender tile, Vec3i relBlockInChunk, RelFace face) {
if (!(tile instanceof TileOptimizedSurface))
return;
TileOptimizedSurface tos = (TileOptimizedSurface) tile;
addTile(pos, face, tos);
addTile(relBlockInChunk, face, tos);
}
protected void addBlock(Vec3i pos, BlockOptimizedSurface block) {
getBlock(pos).block = block;
private void addBlock(Vec3i relBlockInChunk, BlockOptimizedSurface block) {
getBlock(relBlockInChunk).block = block;
}
private void addTile(Vec3i pos, AbsFace face, TileOptimizedSurface tile) {
FaceInfo faceInfo = getFace(pos, face);
private void addTile(Vec3i relBlockInChunk, RelFace face, TileOptimizedSurface tile) {
FaceInfo faceInfo = getFace(relBlockInChunk, face);
int index = faceInfo.tileCount;
faceInfo.tileCount++;
@ -197,12 +200,12 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
}
}
protected BlockInfo getBlock(Vec3i cursor) {
return data[cursor.x][cursor.y][cursor.z];
protected BlockInfo getBlock(Vec3i relBlockInChunk) {
return data[relBlockInChunk.x][relBlockInChunk.y][relBlockInChunk.z];
}
protected FaceInfo getFace(Vec3i cursor, AbsFace face) {
return getBlock(cursor).faces[face.getId()];
protected FaceInfo getFace(Vec3i relBlockInChunk, RelFace face) {
return getBlock(relBlockInChunk).faces[face.getId()];
}
@Override
@ -211,17 +214,12 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3
);
Vec3i cursor = new Vec3i();
Consumer<ShapePart> consumer = shapeParts::add;
for (cursor.x = 0; cursor.x < BLOCKS_PER_CHUNK; ++cursor.x) {
for (cursor.y = 0; cursor.y < BLOCKS_PER_CHUNK; ++cursor.y) {
for (cursor.z = 0; cursor.z < BLOCKS_PER_CHUNK; ++cursor.z) {
processInnerFaces(cursor, consumer);
processOuterFaces(cursor, consumer);
}
}
}
chunk.forEachBiC(relBlockInChunk -> {
processInnerFaces(relBlockInChunk, consumer);
processOuterFaces(relBlockInChunk, consumer);
});
if (shapeParts.isEmpty()) {
return null;
@ -235,25 +233,25 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
}
private void processOuterFaces(
Vec3i blockInChunk,
Vec3i relBlockInChunk,
Consumer<ShapePart> output
) {
for (AbsFace blockFace : AbsFace.getFaces()) {
processOuterFace(blockInChunk, blockFace, output);
for (RelFace blockFace : RelFace.getFaces()) {
processOuterFace(relBlockInChunk, blockFace, output);
}
}
private void processOuterFace(Vec3i blockInChunk, AbsFace blockFace, Consumer<ShapePart> output) {
if (!shouldRenderOuterFace(blockInChunk, blockFace))
private void processOuterFace(Vec3i relBlockInChunk, RelFace blockFace, Consumer<ShapePart> output) {
if (!shouldRenderOuterFace(relBlockInChunk, blockFace))
return;
FaceInfo info = getFace(blockInChunk, blockFace);
FaceInfo info = getFace(relBlockInChunk, blockFace);
if (info.tileCount == 0 && info.block.block == null)
return;
Vec3 faceOrigin = new Vec3(blockInChunk.x, blockInChunk.y, blockInChunk.z);
Vec3 offset = new Vec3(blockFace.getFloatVector()).mul(OVERLAY_OFFSET);
Vec3 faceOrigin = new Vec3(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z);
Vec3 offset = new Vec3(blockFace.getRelFloatVector()).mul(OVERLAY_OFFSET);
for (
int layer = info.topOpaqueSurface;
@ -264,32 +262,29 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
if (surface == null)
continue; // layer may be BLOCK_LAYER, then block may be null
surface.getShapeParts(chunk.getData(), blockInChunk, blockFace, false, output, faceOrigin);
surface.getShapeParts(chunk.getData(), relBlockInChunk, blockFace, false, output, faceOrigin);
faceOrigin.add(offset);
}
}
private void processInnerFaces(
Vec3i blockInChunk,
Consumer<ShapePart> output
) {
for (AbsFace blockFace : AbsFace.getFaces()) {
processInnerFace(blockInChunk, blockFace, output);
private void processInnerFaces(Vec3i relBlockInChunk, Consumer<ShapePart> output) {
for (RelFace blockFace : RelFace.getFaces()) {
processInnerFace(relBlockInChunk, blockFace, output);
}
}
private void processInnerFace(Vec3i blockInChunk, AbsFace blockFace, Consumer<ShapePart> output) {
if (!shouldRenderInnerFace(blockInChunk, blockFace))
private void processInnerFace(Vec3i relBlockInChunk, RelFace blockFace, Consumer<ShapePart> output) {
if (!shouldRenderInnerFace(relBlockInChunk, blockFace))
return;
FaceInfo info = getFace(blockInChunk, blockFace);
FaceInfo info = getFace(relBlockInChunk, blockFace);
if (info.tileCount == 0 && info.block.block == null)
return;
Vec3 faceOrigin = new Vec3(blockInChunk.x, blockInChunk.y, blockInChunk.z);
Vec3 offset = new Vec3(blockFace.getFloatVector()).mul(OVERLAY_OFFSET);
Vec3 faceOrigin = new Vec3(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z);
Vec3 offset = new Vec3(blockFace.getRelFloatVector()).mul(OVERLAY_OFFSET);
for (
int layer = FaceInfo.BLOCK_LAYER;
@ -300,35 +295,35 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
if (surface == null)
continue; // layer may be BLOCK_LAYER, then block may be null
surface.getShapeParts(chunk.getData(), blockInChunk, blockFace, true, output, faceOrigin);
surface.getShapeParts(chunk.getData(), relBlockInChunk, blockFace, true, output, faceOrigin);
faceOrigin.add(offset);
}
}
private boolean shouldRenderOuterFace(Vec3i blockInChunk, AbsFace face) {
blockInChunk.add(face.getVector());
private boolean shouldRenderOuterFace(Vec3i relBlockInChunk, RelFace face) {
relBlockInChunk.add(face.getRelVector());
try {
return shouldRenderWhenFacing(blockInChunk, face);
return shouldRenderWhenFacing(relBlockInChunk, face);
} finally {
blockInChunk.sub(face.getVector());
relBlockInChunk.sub(face.getRelVector());
}
}
private boolean shouldRenderInnerFace(Vec3i blockInChunk, AbsFace face) {
return shouldRenderWhenFacing(blockInChunk, face);
private boolean shouldRenderInnerFace(Vec3i relBlockInChunk, RelFace face) {
return shouldRenderWhenFacing(relBlockInChunk, face);
}
private boolean shouldRenderWhenFacing(Vec3i blockInChunk, AbsFace face) {
if (chunk.containsBiC(blockInChunk)) {
return shouldRenderWhenFacingLocal(blockInChunk, face);
private boolean shouldRenderWhenFacing(Vec3i relBlockInChunk, RelFace face) {
if (chunk.containsBiC(relBlockInChunk)) {
return shouldRenderWhenFacingLocal(relBlockInChunk, face);
} else {
return shouldRenderWhenFacingNeighbor(blockInChunk, face);
return shouldRenderWhenFacingNeighbor(relBlockInChunk, face);
}
}
private boolean shouldRenderWhenFacingLocal(Vec3i blockInChunk, AbsFace face) {
BlockOptimizedSurface block = getBlock(blockInChunk).block;
private boolean shouldRenderWhenFacingLocal(Vec3i relBlockInChunk, RelFace face) {
BlockOptimizedSurface block = getBlock(relBlockInChunk).block;
if (block == null) {
return true;
@ -340,36 +335,37 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
return true;
}
private boolean shouldRenderWhenFacingNeighbor(Vec3i blockInLocalChunk, AbsFace face) {
Vec3i blockInChunk = Vectors.grab3i().set(blockInLocalChunk.x, blockInLocalChunk.y, blockInLocalChunk.z);
private boolean shouldRenderWhenFacingNeighbor(Vec3i relBlockInLocalChunk, RelFace face) {
Vec3i blockInChunk = Vectors.grab3i();
chunk.resolve(relBlockInLocalChunk, blockInChunk);
Vec3i chunkPos = Vectors.grab3i().set(chunk.getX(), chunk.getY(), chunk.getZ());
try {
// Determine blockInChunk and chunkPos
if (blockInLocalChunk.x == -1) {
if (blockInChunk.x == -1) {
blockInChunk.x = BLOCKS_PER_CHUNK - 1;
chunkPos.x -= 1;
} else if (blockInLocalChunk.x == BLOCKS_PER_CHUNK) {
} else if (blockInChunk.x == BLOCKS_PER_CHUNK) {
blockInChunk.x = 0;
chunkPos.x += 1;
} else if (blockInLocalChunk.y == -1) {
} else if (blockInChunk.y == -1) {
blockInChunk.y = BLOCKS_PER_CHUNK - 1;
chunkPos.y -= 1;
} else if (blockInLocalChunk.y == BLOCKS_PER_CHUNK) {
} else if (blockInChunk.y == BLOCKS_PER_CHUNK) {
blockInChunk.y = 0;
chunkPos.y += 1;
} else if (blockInLocalChunk.z == -1) {
} else if (blockInChunk.z == -1) {
blockInChunk.z = BLOCKS_PER_CHUNK - 1;
chunkPos.z -= 1;
} else if (blockInLocalChunk.z == BLOCKS_PER_CHUNK) {
} else if (blockInChunk.z == BLOCKS_PER_CHUNK) {
blockInChunk.z = 0;
chunkPos.z += 1;
} else {
throw new AssertionError(
"Requested incorrent neighbor ("
+ blockInLocalChunk.x + "; "
+ blockInLocalChunk.y + "; "
+ blockInLocalChunk.z + ")"
+ relBlockInLocalChunk.x + "; "
+ relBlockInLocalChunk.y + "; "
+ relBlockInLocalChunk.z + ")"
);
}
@ -382,8 +378,11 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
return true;
BlockOptimizedSurface bos = (BlockOptimizedSurface) block;
if (!bos.isOpaque(face))
RelFace rotatedFace = face.rotate(this.chunk.getUp(), chunk.getUp());
if (!bos.isOpaque(rotatedFace)) {
return true;
}
return false;

View File

@ -18,14 +18,13 @@
package ru.windcorp.progressia.client.world.tile;
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.client.graphics.model.Renderable;
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizer;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.generic.GenericTile;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public class TileRender extends Namespaced implements GenericTile {
@ -33,13 +32,7 @@ public class TileRender extends Namespaced implements GenericTile {
super(id);
}
public void render(ShapeRenderHelper renderer, AbsFace face) {
throw new UnsupportedOperationException(
"TileRender.render() not implemented in " + this
);
}
public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, AbsFace face) {
public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, RelFace face) {
return null;
}

View File

@ -21,7 +21,7 @@ import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.client.graphics.model.EmptyModel;
import ru.windcorp.progressia.client.graphics.model.Renderable;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public class TileRenderNone extends TileRender {
@ -30,7 +30,7 @@ public class TileRenderNone extends TileRender {
}
@Override
public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, AbsFace face) {
public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, RelFace face) {
return EmptyModel.getInstance();
}

View File

@ -19,7 +19,7 @@
package ru.windcorp.progressia.client.world.tile;
import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public class TileRenderOpaqueSurface extends TileRenderSurface {
@ -28,7 +28,7 @@ public class TileRenderOpaqueSurface extends TileRenderSurface {
}
@Override
public boolean isOpaque(AbsFace face) {
public boolean isOpaque(RelFace face) {
return true;
}

View File

@ -35,6 +35,7 @@ import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface.TileO
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public abstract class TileRenderSurface extends TileRender implements TileOptimizedSurface {
@ -49,26 +50,26 @@ public abstract class TileRenderSurface extends TileRender implements TileOptimi
this(id, null);
}
public Texture getTexture(AbsFace blockFace) {
public Texture getTexture(RelFace blockFace) {
return texture;
}
public Vec4 getColorMultiplier(AbsFace blockFace) {
public Vec4 getColorMultiplier(RelFace blockFace) {
return Colors.WHITE;
}
@Override
public final void getShapeParts(
ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace,
ChunkData chunk, Vec3i relBlockInChunk, RelFace blockFace,
boolean inner,
Consumer<ShapePart> output,
Vec3 offset
) {
output.accept(createFace(chunk, blockInChunk, blockFace, inner, offset));
output.accept(createFace(chunk, relBlockInChunk, blockFace, inner, offset));
}
private ShapePart createFace(
ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace,
ChunkData chunk, Vec3i blockInChunk, RelFace blockFace,
boolean inner,
Vec3 offset
) {
@ -77,13 +78,13 @@ public abstract class TileRenderSurface extends TileRender implements TileOptimi
getTexture(blockFace),
getColorMultiplier(blockFace),
offset,
blockFace,
blockFace.resolve(AbsFace.POS_Z),
inner
);
}
@Override
public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace) {
public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, RelFace blockFace) {
return new Shape(
Usage.STATIC,
WorldRenderProgram.getDefault(),

View File

@ -19,7 +19,7 @@
package ru.windcorp.progressia.client.world.tile;
import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public class TileRenderTransparentSurface extends TileRenderSurface {
@ -28,7 +28,7 @@ public class TileRenderTransparentSurface extends TileRenderSurface {
}
@Override
public boolean isOpaque(AbsFace face) {
public boolean isOpaque(RelFace face) {
return false;
}

View File

@ -18,7 +18,7 @@
package ru.windcorp.progressia.common.world;
import static ru.windcorp.progressia.common.world.rels.AbsFace.*;
import static ru.windcorp.progressia.common.world.rels.BlockFace.BLOCK_FACE_COUNT;
import java.util.ArrayList;
import java.util.Arrays;
@ -33,6 +33,8 @@ import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.generic.GenericChunk;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.BlockFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.common.world.tile.TileDataStack;
import ru.windcorp.progressia.common.world.tile.TileReference;
@ -51,6 +53,8 @@ public class ChunkData
private final TileDataStack[] tiles = new TileDataStack[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK *
BLOCK_FACE_COUNT];
private final AbsFace up;
private Object generationHint = null;
private final Collection<ChunkDataListener> listeners = Collections.synchronizedCollection(new ArrayList<>());
@ -58,6 +62,7 @@ public class ChunkData
public ChunkData(Vec3i position, WorldData world) {
this.position.set(position.x, position.y, position.z);
this.world = world;
this.up = world.getGravityModel().getDiscreteUp(position);
}
@Override
@ -65,6 +70,11 @@ public class ChunkData
return position;
}
@Override
public AbsFace getUp() {
return up;
}
@Override
public BlockData getBlock(Vec3i posInChunk) {
return blocks[getBlockIndex(posInChunk)];
@ -83,31 +93,31 @@ public class ChunkData
}
@Override
public TileDataStack getTilesOrNull(Vec3i blockInChunk, AbsFace face) {
public TileDataStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) {
return tiles[getTileIndex(blockInChunk, face)];
}
/**
* Internal use only. Modify a list returned by
* {@link #getTiles(Vec3i, AbsFace)} or
* {@link #getTilesOrNull(Vec3i, AbsFace)}
* {@link #getTiles(Vec3i, BlockFace)} or
* {@link #getTilesOrNull(Vec3i, BlockFace)}
* to change tiles.
*/
protected void setTiles(
Vec3i blockInChunk,
AbsFace face,
BlockFace face,
TileDataStack tiles
) {
this.tiles[getTileIndex(blockInChunk, face)] = tiles;
}
@Override
public boolean hasTiles(Vec3i blockInChunk, AbsFace face) {
public boolean hasTiles(Vec3i blockInChunk, BlockFace face) {
return getTilesOrNull(blockInChunk, face) != null;
}
@Override
public TileDataStack getTiles(Vec3i blockInChunk, AbsFace face) {
public TileDataStack getTiles(Vec3i blockInChunk, BlockFace face) {
int index = getTileIndex(blockInChunk, face);
if (tiles[index] == null) {
@ -117,7 +127,7 @@ public class ChunkData
return tiles[index];
}
private void createTileStack(Vec3i blockInChunk, AbsFace face) {
private void createTileStack(Vec3i blockInChunk, BlockFace face) {
Vec3i independentBlockInChunk = conjureIndependentBlockInChunkVec3i(blockInChunk);
TileDataStackImpl stack = new TileDataStackImpl(independentBlockInChunk, face);
setTiles(blockInChunk, face, stack);
@ -142,15 +152,15 @@ public class ChunkData
posInChunk.x;
}
private static int getTileIndex(Vec3i posInChunk, AbsFace face) {
private int getTileIndex(Vec3i posInChunk, BlockFace face) {
return getBlockIndex(posInChunk) * BLOCK_FACE_COUNT +
face.getId();
face.resolve(getUp()).getId();
}
private static void checkLocalCoordinates(Vec3i posInChunk) {
if (!isInBounds(posInChunk)) {
throw new IllegalCoordinatesException(
"Coordinates " + str(posInChunk) + " "
"Coordinates (" + posInChunk.x + "; " + posInChunk.y + "; " + posInChunk.z + ") "
+ "are not legal chunk coordinates"
);
}
@ -162,14 +172,15 @@ public class ChunkData
posInChunk.z >= 0 && posInChunk.z < BLOCKS_PER_CHUNK;
}
public boolean isBorder(Vec3i blockInChunk, AbsFace face) {
public boolean isBorder(Vec3i blockInChunk, BlockFace face) {
final int min = 0, max = BLOCKS_PER_CHUNK - 1;
return (blockInChunk.x == min && face == NEG_X) ||
(blockInChunk.x == max && face == POS_X) ||
(blockInChunk.y == min && face == NEG_Y) ||
(blockInChunk.y == max && face == POS_Y) ||
(blockInChunk.z == min && face == NEG_Z) ||
(blockInChunk.z == max && face == POS_Z);
AbsFace absFace = face.resolve(getUp());
return (blockInChunk.x == min && absFace == AbsFace.NEG_X) ||
(blockInChunk.x == max && absFace == AbsFace.POS_X) ||
(blockInChunk.y == min && absFace == AbsFace.NEG_Y) ||
(blockInChunk.y == max && absFace == AbsFace.POS_Y) ||
(blockInChunk.z == min && absFace == AbsFace.NEG_Z) ||
(blockInChunk.z == max && absFace == AbsFace.POS_Z);
}
public void forEachBlock(Consumer<Vec3i> action) {
@ -221,10 +232,6 @@ public class ChunkData
this.listeners.remove(listener);
}
private static String str(Vec3i v) {
return "(" + v.x + "; " + v.y + "; " + v.z + ")";
}
protected void onLoaded() {
getListeners().forEach(l -> l.onChunkLoaded(this));
}
@ -309,11 +316,11 @@ public class ChunkData
* Potentially shared
*/
private final Vec3i blockInChunk;
private final AbsFace face;
private final RelFace face;
public TileDataStackImpl(Vec3i blockInChunk, AbsFace face) {
public TileDataStackImpl(Vec3i blockInChunk, BlockFace face) {
this.blockInChunk = blockInChunk;
this.face = face;
this.face = face.relativize(getUp());
}
@Override
@ -325,7 +332,7 @@ public class ChunkData
}
@Override
public AbsFace getFace() {
public RelFace getFace() {
return face;
}
@ -389,7 +396,7 @@ public class ChunkData
references[index] = null;
for (int tag = 0; tag < indicesByTag.length; ++tag) {
if (tagsByIndex[tag] == -1) {
if (indicesByTag[tag] == -1) {
indicesByTag[tag] = index;
tagsByIndex[index] = tag;
break;
@ -406,20 +413,28 @@ public class ChunkData
public void load(TileData tile, int tag) {
addFarthest(tile);
int assignedTag = getIndexByTag(tag);
int assignedIndex = size() - 1;
if (assignedTag == tag)
// Skip if we already have the correct tag
int assignedTag = getTagByIndex(assignedIndex);
if (assignedTag == tag) {
return;
if (assignedTag == -1) {
}
assert assignedTag != -1 : "Adding farthest tile resulted in -1 tag";
// Make sure we aren't trying to assign a tag already in use
int tileWithRequestedTag = getIndexByTag(tag);
if (tileWithRequestedTag != -1) {
throw new IllegalArgumentException(
"Tag " + tag + " already used by tile at index " + getIndexByTag(tag)
"Tag " + tag + " already used by tile at index " + tileWithRequestedTag
);
}
assert tileWithRequestedTag != assignedIndex : "tag == assignedTag yet tileWithRequestedTag != assignedIndex";
indicesByTag[tagsByIndex[size() - 1]] = -1;
tagsByIndex[size() - 1] = tag;
indicesByTag[tag] = size() - 1;
// Do the tag editing
indicesByTag[assignedTag] = -1; // Release assigned tag
tagsByIndex[assignedIndex] = tag; // Reroute assigned index to requested tag
indicesByTag[tag] = assignedIndex; // Claim requested tag
assert checkConsistency();
}

View File

@ -20,7 +20,7 @@ package ru.windcorp.progressia.common.world;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.tile.TileData;
public interface ChunkDataListener {
@ -55,7 +55,7 @@ public interface ChunkDataListener {
default void onChunkTilesChanged(
ChunkData chunk,
Vec3i blockInChunk,
AbsFace face,
RelFace face,
TileData tile,
boolean wasAdded
) {

View File

@ -25,6 +25,8 @@ import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.BlockFace;
import ru.windcorp.progressia.common.world.rels.RelRelation;
public interface GenericChunk<Self extends GenericChunk<Self, B, T, TS>, B extends GenericBlock, T extends GenericTile, TS extends GenericTileStack<TS, T, Self>> {
@ -32,11 +34,54 @@ public interface GenericChunk<Self extends GenericChunk<Self, B, T, TS>, B exten
Vec3i getPosition();
AbsFace getUp();
B getBlock(Vec3i blockInChunk);
TS getTiles(Vec3i blockInChunk, AbsFace face);
TS getTiles(Vec3i blockInChunk, BlockFace face);
boolean hasTiles(Vec3i blockInChunk, AbsFace face);
boolean hasTiles(Vec3i blockInChunk, BlockFace face);
default Vec3i resolve(Vec3i relativeBlockInChunk, Vec3i output) {
if (output == null) {
output = new Vec3i();
}
final int offset = BLOCKS_PER_CHUNK - 1;
output.set(relativeBlockInChunk.x, relativeBlockInChunk.y, relativeBlockInChunk.z);
output.mul(2).sub(offset);
RelRelation.resolve(output, getUp(), output);
output.add(offset).div(2);
return output;
}
default B getBlockRel(Vec3i relativeBlockInChunk) {
Vec3i absoluteBlockInChunk = Vectors.grab3i();
resolve(relativeBlockInChunk, absoluteBlockInChunk);
B result = getBlock(absoluteBlockInChunk);
Vectors.release(absoluteBlockInChunk);
return result;
}
default TS getTilesRel(Vec3i relativeBlockInChunk, BlockFace face) {
Vec3i absoluteBlockInChunk = Vectors.grab3i();
resolve(relativeBlockInChunk, absoluteBlockInChunk);
TS result = getTiles(absoluteBlockInChunk, face);
Vectors.release(absoluteBlockInChunk);
return result;
}
default boolean hasTilesRel(Vec3i relativeBlockInChunk, BlockFace face) {
Vec3i absoluteBlockInChunk = Vectors.grab3i();
resolve(relativeBlockInChunk, absoluteBlockInChunk);
boolean result = hasTiles(absoluteBlockInChunk, face);
Vectors.release(absoluteBlockInChunk);
return result;
}
default int getX() {
return getPosition().x;
@ -182,7 +227,7 @@ public interface GenericChunk<Self extends GenericChunk<Self, B, T, TS>, B exten
);
}
default TS getTilesOrNull(Vec3i blockInChunk, AbsFace face) {
default TS getTilesOrNull(Vec3i blockInChunk, BlockFace face) {
if (hasTiles(blockInChunk, face)) {
return getTiles(blockInChunk, face);
}
@ -190,4 +235,21 @@ public interface GenericChunk<Self extends GenericChunk<Self, B, T, TS>, B exten
return null;
}
default TS getTilesOrNullRel(Vec3i relativeBlockInChunk, BlockFace face) {
Vec3i absoluteBlockInChunk = Vectors.grab3i();
resolve(relativeBlockInChunk, absoluteBlockInChunk);
TS result;
if (hasTiles(absoluteBlockInChunk, face)) {
result = getTiles(absoluteBlockInChunk, face);
} else {
result = null;
}
Vectors.release(absoluteBlockInChunk);
return result;
}
}

View File

@ -25,7 +25,7 @@ import java.util.function.Consumer;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public abstract class GenericTileStack<Self extends GenericTileStack<Self, T, C>, T extends GenericTile, C extends GenericChunk<C, ?, T, Self>>
extends AbstractList<T>
@ -41,7 +41,7 @@ public abstract class GenericTileStack<Self extends GenericTileStack<Self, T, C>
public abstract C getChunk();
public abstract AbsFace getFace();
public abstract RelFace getFace();
public Vec3i getBlockInWorld(Vec3i output) {
// This is safe

View File

@ -27,6 +27,7 @@ import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.BlockFace;
public interface GenericWorld<B extends GenericBlock, T extends GenericTile, TS extends GenericTileStack<TS, T, C>, C extends GenericChunk<C, B, T, TS>, E extends GenericEntity> {
@ -48,6 +49,10 @@ public interface GenericWorld<B extends GenericBlock, T extends GenericTile, TS
return result;
}
default AbsFace getUp(Vec3i blockInWorld) {
return getChunkByBlock(blockInWorld).getUp();
}
default B getBlock(Vec3i blockInWorld) {
Vec3i v = Vectors.grab3i();
B result;
@ -63,7 +68,7 @@ public interface GenericWorld<B extends GenericBlock, T extends GenericTile, TS
return result;
}
default TS getTiles(Vec3i blockInWorld, AbsFace face) {
default TS getTiles(Vec3i blockInWorld, BlockFace face) {
Vec3i v = Vectors.grab3i();
TS result;
@ -78,7 +83,7 @@ public interface GenericWorld<B extends GenericBlock, T extends GenericTile, TS
return result;
}
default TS getTilesOrNull(Vec3i blockInWorld, AbsFace face) {
default TS getTilesOrNull(Vec3i blockInWorld, BlockFace face) {
Vec3i v = Vectors.grab3i();
TS result;
@ -93,7 +98,7 @@ public interface GenericWorld<B extends GenericBlock, T extends GenericTile, TS
return result;
}
default boolean hasTiles(Vec3i blockInWorld, AbsFace face) {
default boolean hasTiles(Vec3i blockInWorld, BlockFace face) {
Vec3i v = Vectors.grab3i();
boolean result;
@ -108,7 +113,7 @@ public interface GenericWorld<B extends GenericBlock, T extends GenericTile, TS
return result;
}
default T getTile(Vec3i blockInWorld, AbsFace face, int layer) {
default T getTile(Vec3i blockInWorld, BlockFace face, int layer) {
TS stack = getTilesOrNull(blockInWorld, face);
if (stack == null || stack.size() <= layer)
return null;

View File

@ -26,7 +26,7 @@ import com.google.common.collect.ImmutableMap;
import glm.vec._3.Vec3;
import glm.vec._3.i.Vec3i;
public final class AbsFace extends AbsRelation {
public final class AbsFace extends AbsRelation implements BlockFace {
// @formatter:off
public static final AbsFace
@ -52,7 +52,6 @@ public final class AbsFace extends AbsRelation {
private static final ImmutableList<AbsFace> SECONDARY_FACES = ALL_FACES.stream().filter(AbsFace::isSecondary)
.collect(ImmutableList.toImmutableList());
public static final int BLOCK_FACE_COUNT = ALL_FACES.size();
public static final int PRIMARY_BLOCK_FACE_COUNT = PRIMARY_FACES.size();
public static final int SECONDARY_BLOCK_FACE_COUNT = SECONDARY_FACES.size();
@ -227,6 +226,16 @@ public final class AbsFace extends AbsRelation {
return name;
}
@Override
public AbsFace resolve(AbsFace up) {
return this;
}
@Override
public RelFace relativize(AbsFace up) {
return BlockFaceResolver.relativize(this, up);
}
public boolean isPrimary() {
return isPrimary;
}

View File

@ -41,6 +41,18 @@ public class AbsRelation extends BlockRelation {
this(vector.x, vector.y, vector.z);
}
public static AbsRelation of(Vec3i vector) {
return of(vector.x, vector.y, vector.z);
}
public static AbsRelation of(int x, int y, int z) {
if (Math.abs(x) + Math.abs(y) + Math.abs(z) == 1) {
return AbsFace.roundToFace(x, y, z);
}
return new AbsRelation(x, y, z);
}
@Override
public AbsRelation resolve(AbsFace up) {
return this;

View File

@ -0,0 +1,42 @@
/*
* 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 glm.vec._3.Vec3;
import glm.vec._3.i.Vec3i;
public interface BlockFace {
public static final int BLOCK_FACE_COUNT = 6;
AbsFace resolve(AbsFace up);
RelFace relativize(AbsFace up);
public default Vec3i getVector(AbsFace up) {
return resolve(up).getVector();
}
public default Vec3 getFloatVector(AbsFace up) {
return resolve(up).getFloatVector();
}
public default Vec3 getNormalized(AbsFace up) {
return resolve(up).getNormalized();
}
}

View File

@ -0,0 +1,78 @@
/*
* 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 java.util.Objects;
import static ru.windcorp.progressia.common.world.rels.AbsFace.BLOCK_FACE_COUNT;
public class BlockFaceResolver {
/**
* A mapping from (up; relative) to absolute. Face IDs are used as keys.
*/
private static final AbsFace[][] RESOLUTION_TABLE = new AbsFace[BLOCK_FACE_COUNT][BLOCK_FACE_COUNT];
/**
* A mapping from (up; absolute) to relative. Face IDs are used as keys.
*/
private static final RelFace[][] RELATIVIZATION_TABLE = new RelFace[BLOCK_FACE_COUNT][BLOCK_FACE_COUNT];
static {
for (AbsFace up : AbsFace.getFaces()) {
for (RelFace relative : RelFace.getFaces()) {
AbsFace absolute = (AbsFace) AbsRelation.of(RelRelation.resolve(relative.getRelVector(), up, null));
RESOLUTION_TABLE[up.getId()][relative.getId()] = absolute;
RELATIVIZATION_TABLE[up.getId()][absolute.getId()] = relative;
}
}
}
public static AbsFace resolve(RelFace relative, AbsFace up) {
Objects.requireNonNull(relative, "relative");
Objects.requireNonNull(up, "up");
if (relative == RelFace.UP) {
return up;
} else if (relative == RelFace.DOWN) {
return up.getCounter();
}
return RESOLUTION_TABLE[up.getId()][relative.getId()];
}
public static RelFace relativize(AbsFace absolute, AbsFace up) {
Objects.requireNonNull(absolute, "absolute");
Objects.requireNonNull(up, "up");
if (absolute == up) {
return RelFace.UP;
} else if (absolute.getCounter() == up) {
return RelFace.DOWN;
}
return RELATIVIZATION_TABLE[up.getId()][absolute.getId()];
}
private BlockFaceResolver() {
}
}

View File

@ -22,7 +22,7 @@ import com.google.common.collect.ImmutableMap;
import glm.vec._3.i.Vec3i;
public class RelFace extends RelRelation {
public class RelFace extends RelRelation implements BlockFace {
// @formatter:off
public static final RelFace
@ -76,7 +76,7 @@ public class RelFace extends RelRelation {
private RelFace counterFace;
private RelFace(int x, int y, int z, String name) {
super(x, y, z, true);
super(x, y, z, false);
this.id = nextId++;
this.name = name;
}
@ -85,6 +85,24 @@ public class RelFace extends RelRelation {
return name;
}
@Override
public AbsFace resolve(AbsFace up) {
return BlockFaceResolver.resolve(this, up);
}
@Override
public RelFace relativize(AbsFace up) {
return this;
}
public RelFace rotate(AbsFace fromUp, AbsFace toUp) {
if (fromUp == toUp) {
return this;
}
return resolve(fromUp).relativize(toUp);
}
/**
* @return the id
*/
@ -97,7 +115,7 @@ public class RelFace extends RelRelation {
}
public RelFace getCounterAndMoveCursor(Vec3i cursor) {
cursor.add(getVector());
cursor.add(getRelVector());
return counterFace;
}

View File

@ -19,8 +19,12 @@ package ru.windcorp.progressia.common.world.rels;
import java.util.Map;
import glm.mat._3.Mat3;
import glm.mat._4.Mat4;
import glm.vec._3.Vec3;
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.VectorUtil.SignedAxis;
import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.*;
@ -35,20 +39,64 @@ public class RelRelation extends BlockRelation {
private final SignedAxis westDestination;
private final SignedAxis upDestination;
public Rotation(SignedAxis northDestination, SignedAxis westDestination, SignedAxis upDestination) {
private final Mat3 resolutionMatrix3 = new Mat3();
private final Mat4 resolutionMatrix4 = new Mat4();
private final Mat3 relativizationMatrix3 = new Mat3();
private final Mat4 relativizationMatrix4 = new Mat4();
private Rotation(SignedAxis northDestination, SignedAxis westDestination, SignedAxis upDestination) {
this.northDestination = northDestination;
this.westDestination = westDestination;
this.upDestination = upDestination;
resolutionMatrix3.c0(apply(null, new Vec3(1, 0, 0)));
resolutionMatrix3.c1(apply(null, new Vec3(0, 1, 0)));
resolutionMatrix3.c2(apply(null, new Vec3(0, 0, 1)));
resolutionMatrix3.toMat4(resolutionMatrix4);
relativizationMatrix3.set(resolutionMatrix3).transpose();
relativizationMatrix4.set(resolutionMatrix4).transpose();
}
/**
* @return the resolutionMatrix3
*/
public Mat3 getResolutionMatrix3() {
return resolutionMatrix3;
}
/**
* @return the resolutionMatrix4
*/
public Mat4 getResolutionMatrix4() {
return resolutionMatrix4;
}
/**
* @return the relativizationMatrix3
*/
public Mat3 getRelativizationMatrix3() {
return relativizationMatrix3;
}
/**
* @return the relativizationMatrix4
*/
public Mat4 getRelativizationMatrix4() {
return relativizationMatrix4;
}
public Vec3i apply(Vec3i output, Vec3i input) {
if (output == null) {
return output;
output = new Vec3i();
}
set(output, input.x, northDestination);
set(output, input.y, westDestination);
set(output, input.z, upDestination);
int inX = input.x, inY = input.y, inZ = input.z;
set(output, inX, northDestination);
set(output, inY, westDestination);
set(output, inZ, upDestination);
return output;
}
@ -56,6 +104,24 @@ public class RelRelation extends BlockRelation {
private static void set(Vec3i output, int value, SignedAxis axis) {
VectorUtil.set(output, axis.getAxis(), axis.isPositive() ? +value : -value);
}
public Vec3 apply(Vec3 output, Vec3 input) {
if (output == null) {
output = new Vec3();
}
float inX = input.x, inY = input.y, inZ = input.z;
set(output, inX, northDestination);
set(output, inY, westDestination);
set(output, inZ, upDestination);
return output;
}
private static void set(Vec3 output, float value, SignedAxis axis) {
VectorUtil.set(output, axis.getAxis(), axis.isPositive() ? +value : -value);
}
}
private final static Map<AbsFace, Rotation> TRANSFORMATIONS = AbsFace.mapToFaces(
@ -68,14 +134,27 @@ public class RelRelation extends BlockRelation {
);
private final Vec3i vector = new Vec3i();
private final Vec3 floatVector = new Vec3();
private final Vec3 normalized = new Vec3();
private AbsRelation[] resolved = null;
public RelRelation(int north, int west, int up) {
this(north, west, up, false);
}
public RelRelation(Vec3i vector) {
this(vector.x, vector.y, vector.z, false);
}
protected RelRelation(int north, int west, int up, boolean precomputeAllResolutions) {
vector.set(north, west, up);
floatVector.set(north, west, up);
normalized.set(north, west, up);
if (normalized.any()) {
normalized.normalize();
}
if (precomputeAllResolutions) {
for (AbsFace face : AbsFace.getFaces()) {
@ -84,13 +163,46 @@ public class RelRelation extends BlockRelation {
}
}
public static RelRelation of(Vec3i vector) {
return of(vector.x, vector.y, vector.z);
}
public static RelRelation of(int north, int west, int up) {
if (Math.abs(north) + Math.abs(west) + Math.abs(up) == 1) {
if (up == 1) {
return RelFace.UP;
} else if (up == -1) {
return RelFace.DOWN;
} else if (north == 1) {
return RelFace.NORTH;
} else if (north == -1) {
return RelFace.SOUTH;
} else if (west == 1) {
return RelFace.WEST;
} else {
assert west == -1;
return RelFace.EAST;
}
}
return new RelRelation(north, west, up);
}
/**
* @return the relative vector (northward, westward, upward)
*/
public Vec3i getVector() {
public Vec3i getRelVector() {
return vector;
}
public Vec3 getRelFloatVector() {
return floatVector;
}
public Vec3 getRelNormalized() {
return normalized;
}
public int getNorthward() {
return vector.x;
}
@ -129,12 +241,43 @@ public class RelRelation extends BlockRelation {
}
private AbsRelation computeResolution(AbsFace up) {
return new AbsRelation(TRANSFORMATIONS.get(up).apply(new Vec3i(), vector));
Vec3i resolution = Vectors.grab3i();
resolve(vector, up, resolution);
AbsRelation result = AbsRelation.of(resolution);
Vectors.release(resolution);
return result;
}
public static Vec3i resolve(Vec3i relative, AbsFace up, Vec3i output) {
if (output == null) {
output = new Vec3i();
}
TRANSFORMATIONS.get(up).apply(output, relative);
return output;
}
public static Mat3 getResolutionMatrix3(AbsFace up) {
return TRANSFORMATIONS.get(up).getResolutionMatrix3();
}
public static Mat4 getResolutionMatrix4(AbsFace up) {
return TRANSFORMATIONS.get(up).getResolutionMatrix4();
}
public static Mat3 getRelativizationMatrix3(AbsFace up) {
return TRANSFORMATIONS.get(up).getRelativizationMatrix3();
}
public static Mat4 getRelativizationMatrix4(AbsFace up) {
return TRANSFORMATIONS.get(up).getRelativizationMatrix4();
}
@Override
protected Vec3i getSample() {
return getVector();
return getRelVector();
}
}

View File

@ -68,9 +68,9 @@ public class Server {
this.chunkManager = new ChunkManager(this);
this.entityManager = new EntityManager(this);
schedule(this::scheduleWorldTicks);
schedule(chunkManager::tick);
schedule(entityManager::tick);
schedule(this::scheduleWorldTicks); // Must run after chunkManager so it only schedules chunks that hadn't unloaded
}
/**

View File

@ -30,6 +30,8 @@ import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.generic.GenericChunk;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.BlockFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.tile.TileDataStack;
import ru.windcorp.progressia.common.world.tile.TileReference;
import ru.windcorp.progressia.server.world.block.BlockLogic;
@ -67,6 +69,11 @@ public class ChunkLogic implements GenericChunk<ChunkLogic, BlockLogic, TileLogi
return getData().getPosition();
}
@Override
public AbsFace getUp() {
return getData().getUp();
}
@Override
public BlockLogic getBlock(Vec3i blockInChunk) {
return BlockLogicRegistry.getInstance().get(
@ -75,12 +82,12 @@ public class ChunkLogic implements GenericChunk<ChunkLogic, BlockLogic, TileLogi
}
@Override
public TileLogicStack getTiles(Vec3i blockInChunk, AbsFace face) {
public TileLogicStack getTiles(Vec3i blockInChunk, BlockFace face) {
return getTileStackWrapper(getData().getTiles(blockInChunk, face));
}
@Override
public boolean hasTiles(Vec3i blockInChunk, AbsFace face) {
public boolean hasTiles(Vec3i blockInChunk, BlockFace face) {
return getData().hasTiles(blockInChunk, face);
}
@ -149,7 +156,7 @@ public class ChunkLogic implements GenericChunk<ChunkLogic, BlockLogic, TileLogi
}
@Override
public AbsFace getFace() {
public RelFace getFace() {
return parent.getFace();
}

View File

@ -22,6 +22,7 @@ import java.util.function.Consumer;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.server.world.block.BlockTickContext;
public interface ChunkTickContext extends TickContext {
@ -37,6 +38,10 @@ public interface ChunkTickContext extends TickContext {
return chunkLogic == null ? null : chunkLogic.getData();
}
default AbsFace getUp() {
return getChunkData().getUp();
}
default void forEachBlock(Consumer<BlockTickContext> action) {
TickContextMutable context = TickContextMutable.uninitialized();

View File

@ -21,7 +21,7 @@ package ru.windcorp.progressia.server.world;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.BlockFace;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.block.BlockLogic;
import ru.windcorp.progressia.server.world.block.BlockTickContext;
@ -61,17 +61,22 @@ public class TickAndUpdateUtil {
}
}
public static void tickTile(WorldLogic world, Vec3i blockInWorld, AbsFace face, int layer) {
public static void tickTile(WorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) {
TileLogic tile = world.getTile(blockInWorld, face, layer);
if (!(tile instanceof TickableTile))
if (!(tile instanceof TickableTile)) {
return;
}
TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face)
.withLayer(layer);
tickTile((TickableTile) tile, tickContext);
}
public static void tickTiles(WorldLogic world, Vec3i blockInWorld, AbsFace face) {
public static void tickTiles(WorldLogic world, Vec3i blockInWorld, BlockFace face) {
if (!world.isBlockLoaded(blockInWorld)) {
return;
}
TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build()
.forEachTile(context -> {
TileLogic tile = context.getTile();
@ -106,17 +111,22 @@ public class TickAndUpdateUtil {
}
}
public static void updateTile(WorldLogic world, Vec3i blockInWorld, AbsFace face, int layer) {
public static void updateTile(WorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) {
TileLogic tile = world.getTile(blockInWorld, face, layer);
if (!(tile instanceof UpdateableTile))
if (!(tile instanceof UpdateableTile)) {
return;
}
TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face)
.withLayer(layer);
updateTile((UpdateableTile) tile, tickContext);
}
public static void updateTiles(WorldLogic world, Vec3i blockInWorld, AbsFace face) {
public static void updateTiles(WorldLogic world, Vec3i blockInWorld, BlockFace face) {
if (!world.isBlockLoaded(blockInWorld)) {
return;
}
TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build()
.forEachTile(context -> {
TileLogic tile = context.getTile();

View File

@ -26,7 +26,8 @@ import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.generic.GenericTileStack;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.BlockFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.tile.TileDataStack;
import ru.windcorp.progressia.common.world.tile.TileReference;
import ru.windcorp.progressia.server.Server;
@ -126,7 +127,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
}
public static interface Block extends Builder {
Builder.TileStack withFace(AbsFace face);
Builder.TileStack withFace(BlockFace face);
}
public static interface TileStack extends Builder {
@ -148,7 +149,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
protected Server server;
protected final Vec3i chunk = new Vec3i();
protected final Vec3i blockInWorld = new Vec3i();
protected AbsFace face;
protected RelFace face;
protected int layer;
protected Role role = Role.NONE;
@ -188,7 +189,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
}
@Override
public AbsFace getFace() {
public RelFace getFace() {
checkContextState(Role.TILE_STACK);
return this.face;
}
@ -261,8 +262,9 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
public TileStack withTS(GenericTileStack<?, ?, ?> tileStack) {
Objects.requireNonNull(tileStack, "tileStack");
return withBlock(tileStack.getBlockInWorld(this.blockInWorld)).withFace(tileStack.getFace());
// ^^^^^^^^^^^^^^^^^ This is safe
return withBlock(
tileStack.getBlockInWorld(this.blockInWorld) // This is safe
).withFace(tileStack.getFace());
}
@Override
@ -277,11 +279,11 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
}
@Override
public TileStack withFace(AbsFace face) {
public TileStack withFace(BlockFace face) {
Objects.requireNonNull(face, "face");
checkBuilderState(Role.BLOCK);
this.face = face;
this.face = face.relativize(server.getWorld().getChunk(chunk).getUp());
this.role = Role.TILE_STACK;
return this;
@ -339,12 +341,12 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
@Override
public void forEachFace(Consumer<TSTickContext> action) {
checkContextState(Role.BLOCK);
AbsFace previousFace = this.face;
RelFace previousFace = this.face;
Role previousRole = this.role;
this.role = Role.TILE_STACK;
for (int i = 0; i < AbsFace.BLOCK_FACE_COUNT; ++i) {
this.face = AbsFace.getFaces().get(i);
for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) {
this.face = RelFace.getFaces().get(i);
action.accept(this);
}
@ -393,11 +395,13 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
Objects.requireNonNull(action, "action");
checkContextState(Role.TILE_STACK);
this.blockInWorld.add(this.face.getVector());
Vec3i vector = this.face.getVector(getUp());
this.blockInWorld.add(vector);
this.face = this.face.getCounter();
R result = action.apply(this);
this.face = this.face.getCounter();
this.blockInWorld.sub(this.face.getVector());
this.blockInWorld.sub(vector);
return result;
}
@ -407,11 +411,13 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
Objects.requireNonNull(action, "action");
checkContextState(Role.TILE_STACK);
this.blockInWorld.add(this.face.getVector());
Vec3i vector = this.face.getVector(getUp());
this.blockInWorld.add(vector);
this.face = this.face.getCounter();
action.accept(this);
this.face = this.face.getCounter();
this.blockInWorld.sub(this.face.getVector());
this.blockInWorld.sub(vector);
}
/*

View File

@ -23,7 +23,7 @@ import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.ChunkDataListener;
import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.server.Server;
@ -49,7 +49,7 @@ public class UpdateTriggerer implements ChunkDataListener {
public void onChunkTilesChanged(
ChunkData chunk,
Vec3i blockInChunk,
AbsFace face,
RelFace face,
TileData tile,
boolean wasAdded
) {

View File

@ -39,13 +39,8 @@ import ru.windcorp.progressia.server.world.tile.TileLogic;
import ru.windcorp.progressia.server.world.tile.TileLogicStack;
public class WorldLogic
implements GenericWorld<BlockLogic, TileLogic, TileLogicStack, ChunkLogic, EntityData // not
// using
// EntityLogic
// because
// it
// is
// stateless
implements GenericWorld<BlockLogic, TileLogic, TileLogicStack, ChunkLogic, EntityData
// not using EntityLogic because it is stateless
> {
private final WorldData data;

View File

@ -20,7 +20,7 @@ package ru.windcorp.progressia.server.world.block;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
import ru.windcorp.progressia.common.world.generic.GenericBlock;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public class BlockLogic extends Namespaced implements GenericBlock {
@ -28,11 +28,11 @@ public class BlockLogic extends Namespaced implements GenericBlock {
super(id);
}
public boolean isSolid(BlockTickContext context, AbsFace face) {
public boolean isSolid(BlockTickContext context, RelFace face) {
return isSolid(face);
}
public boolean isSolid(AbsFace face) {
public boolean isSolid(RelFace face) {
return true;
}

View File

@ -26,7 +26,7 @@ import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.AbsRelation;
import ru.windcorp.progressia.common.world.rels.BlockRelation;
import ru.windcorp.progressia.server.world.ChunkTickContext;
import ru.windcorp.progressia.server.world.TickContextMutable;
import ru.windcorp.progressia.server.world.tile.TSTickContext;
@ -67,9 +67,9 @@ public interface BlockTickContext extends ChunkTickContext {
return TickContextMutable.copyWorld(this).withBlock(getBlockInWorld().add_(direction)).build();
}
default BlockTickContext getNeighbor(AbsRelation relation) {
default BlockTickContext getNeighbor(BlockRelation relation) {
Objects.requireNonNull(relation, "relation");
return getNeighbor(relation.getVector());
return getNeighbor(relation.getVector(getChunkData().getUp()));
}
default <R> R evalNeighbor(Vec3i direction, Function<BlockTickContext, R> action) {
@ -78,10 +78,10 @@ public interface BlockTickContext extends ChunkTickContext {
return action.apply(getNeighbor(direction));
}
default <R> R evalNeighbor(AbsRelation relation, Function<BlockTickContext, R> action) {
default <R> R evalNeighbor(BlockRelation relation, Function<BlockTickContext, R> action) {
Objects.requireNonNull(action, "action");
Objects.requireNonNull(relation, "relation");
return evalNeighbor(relation.getVector(), action);
return evalNeighbor(relation.getVector(getChunkData().getUp()), action);
}
default void forNeighbor(Vec3i direction, Consumer<BlockTickContext> action) {
@ -93,10 +93,10 @@ public interface BlockTickContext extends ChunkTickContext {
});
}
default void forNeighbor(AbsRelation relation, Consumer<BlockTickContext> action) {
default void forNeighbor(BlockRelation relation, Consumer<BlockTickContext> action) {
Objects.requireNonNull(action, "action");
Objects.requireNonNull(relation, "relation");
forNeighbor(relation.getVector(), action);
forNeighbor(relation.getVector(getChunkData().getUp()), action);
}
/*

View File

@ -25,7 +25,7 @@ import ru.windcorp.progressia.common.util.MultiLOC;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.BlockFace;
import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
import ru.windcorp.progressia.server.Server;
@ -64,19 +64,19 @@ public class WorldAccessor {
setBlock(blockInWorld, BlockDataRegistry.getInstance().get(id));
}
public void addTile(Vec3i blockInWorld, AbsFace face, TileData tile) {
public void addTile(Vec3i blockInWorld, BlockFace face, TileData tile) {
AddTile change = cache.grab(AddTile.class);
change.getPacket().set(tile, blockInWorld, face);
change.getPacket().set(tile, blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld)));
server.requestChange(change);
}
public void addTile(Vec3i blockInWorld, AbsFace face, String id) {
public void addTile(Vec3i blockInWorld, BlockFace face, String id) {
addTile(blockInWorld, face, TileDataRegistry.getInstance().get(id));
}
public void removeTile(Vec3i blockInWorld, AbsFace face, int tag) {
public void removeTile(Vec3i blockInWorld, BlockFace face, int tag) {
RemoveTile change = cache.grab(RemoveTile.class);
change.getPacket().set(blockInWorld, face, tag);
change.getPacket().set(blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld)), tag);
server.requestChange(change);
}
@ -91,6 +91,7 @@ public class WorldAccessor {
public void tickBlock(Vec3i blockInWorld) {
// TODO
System.err.println("WorldAccessor.tickBlock(Vec3i) NYI!");
}
/**
@ -112,9 +113,9 @@ public class WorldAccessor {
* @param face
*/
// TODO rename to something meaningful
public void triggerUpdates(Vec3i blockInWorld, AbsFace face) {
public void triggerUpdates(Vec3i blockInWorld, BlockFace face) {
TileTriggeredUpdate evaluation = cache.grab(TileTriggeredUpdate.class);
evaluation.init(blockInWorld, face);
evaluation.init(blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld)));
server.requestEvaluation(evaluation);
}

View File

@ -23,7 +23,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.tile.TileDataStack;
import ru.windcorp.progressia.server.world.ChunkLogic;
import ru.windcorp.progressia.server.world.TickContextMutable;
@ -35,7 +35,7 @@ public interface TSTickContext extends BlockTickContext {
* Specifications
*/
AbsFace getFace();
RelFace getFace();
/*
* Getters
@ -91,7 +91,7 @@ public interface TSTickContext extends BlockTickContext {
default TSTickContext getComplementary() {
return TickContextMutable.copyWorld(this)
.withBlock(getBlockInWorld().add_(getFace().getVector()))
.withBlock(getBlockInWorld().add_(getFace().getVector(getUp())))
.withFace(getFace().getCounter())
.build();
}

View File

@ -20,7 +20,7 @@ package ru.windcorp.progressia.server.world.tile;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
import ru.windcorp.progressia.common.world.generic.GenericTile;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public class TileLogic extends Namespaced implements GenericTile {
@ -32,7 +32,7 @@ public class TileLogic extends Namespaced implements GenericTile {
return canOccupyFace(context.getFace());
}
public boolean canOccupyFace(AbsFace face) {
public boolean canOccupyFace(RelFace face) {
return true;
}

View File

@ -18,7 +18,7 @@
package ru.windcorp.progressia.test;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.server.world.block.BlockLogic;
public class TestBlockLogicAir extends BlockLogic {
@ -28,7 +28,7 @@ public class TestBlockLogicAir extends BlockLogic {
}
@Override
public boolean isSolid(AbsFace face) {
public boolean isSolid(RelFace face) {
return false;
}

View File

@ -18,7 +18,7 @@
package ru.windcorp.progressia.test;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.server.world.block.BlockLogic;
public class TestBlockLogicGlass extends BlockLogic {
@ -28,7 +28,7 @@ public class TestBlockLogicGlass extends BlockLogic {
}
@Override
public boolean isSolid(AbsFace face) {
public boolean isSolid(RelFace face) {
return false;
}

View File

@ -39,7 +39,7 @@ import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.common.world.io.ChunkCodec;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
@ -91,6 +91,9 @@ public class TestChunkCodec extends ChunkCodec {
TileData[] tilePalette = readTilePalette(input);
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);
@ -138,7 +141,7 @@ public class TestChunkCodec extends ChunkCodec {
break;
bic.set(xOrEndMarker, input.readByte() & 0xFF, input.readByte() & 0xFF);
AbsFace face = AbsFace.getFaces().get(input.readByte() & 0xFF);
RelFace face = RelFace.getFaces().get(input.readByte() & 0xFF);
int tiles = input.readByte() & 0xFF;

View File

@ -137,9 +137,6 @@ public class TestContent {
"Test:Log",
getBlockTexture("LogTop"),
getBlockTexture("LogTop"),
getBlockTexture("LogSide"),
getBlockTexture("LogSide"),
getBlockTexture("LogSide"),
getBlockTexture("LogSide")
)
);
@ -159,7 +156,7 @@ public class TestContent {
Set<String> placeableBlacklist = new HashSet<>();
register(new TileData("Test:Grass"));
register(new TileRenderGrass("Test:Grass", getTileTexture("GrassTop"), getTileTexture("GrassSide")));
register(new TestTileRenderGrass("Test:Grass", getTileTexture("GrassTop"), getTileTexture("GrassSide")));
register(new TestTileLogicGrass("Test:Grass"));
register(new TileData("Test:Stones"));

View File

@ -78,15 +78,8 @@ public class TestEntityRenderJavapony extends EntityRender {
b.addStaticPart(
new PppBuilder(
WorldRenderProgram.getDefault(),
AbsFace.mapToFaces(
tailStartTexture,
tailStartTexture,
tailStartTexture,
tailStartTexture,
tailStartTexture,
tailStartTexture
)
)
.setOrigin(-60, -4, 14)
.setDepth(32, 0, -16).setWidth(8).setHeight(8)
.create()
@ -97,15 +90,8 @@ public class TestEntityRenderJavapony extends EntityRender {
b.addStaticPart(
new PppBuilder(
WorldRenderProgram.getDefault(),
AbsFace.mapToFaces(
neckTexture,
neckTexture,
neckTexture,
neckTexture,
neckTexture,
neckTexture
)
)
.setOrigin(0, -8, 8)
.setWidth(16).setDepth(16).setHeight(2, 0, 16)
.create()

View File

@ -18,7 +18,7 @@
package ru.windcorp.progressia.test;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.server.world.block.BlockLogic;
import ru.windcorp.progressia.server.world.block.BlockTickContext;
import ru.windcorp.progressia.server.world.ticking.TickingPolicy;
@ -34,12 +34,12 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile
@Override
public boolean canOccupyFace(TileTickContext context) {
return context.getFace() != AbsFace.NEG_Z && super.canOccupyFace(context);
return context.getFace() != RelFace.DOWN && super.canOccupyFace(context);
}
@Override
public boolean canOccupyFace(AbsFace face) {
return face != AbsFace.NEG_Z;
public boolean canOccupyFace(RelFace face) {
return face != RelFace.DOWN;
}
@Override
@ -50,7 +50,7 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile
@Override
public void tick(TileTickContext context) {
if (!isLocationSuitable(context)) {
context.removeThisTile();
// context.removeThisTile();
}
}
@ -64,7 +64,7 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile
}
private boolean isBlockAboveTransparent(BlockTickContext context) {
return context.evalNeighbor(AbsFace.POS_Z, bctxt -> {
return context.evalNeighbor(RelFace.UP, bctxt -> {
BlockLogic block = bctxt.getBlock();
if (block == null)
return true;

View File

@ -16,17 +16,18 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.world.tile;
package ru.windcorp.progressia.test;
import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.client.world.tile.TileRenderSurface;
import ru.windcorp.progressia.common.world.rels.RelFace;
public class TileRenderGrass extends TileRenderSurface {
public class TestTileRenderGrass extends TileRenderSurface {
private final Texture topTexture;
private final Texture sideTexture;
public TileRenderGrass(
public TestTileRenderGrass(
String id,
Texture top,
Texture side
@ -37,13 +38,13 @@ public class TileRenderGrass extends TileRenderSurface {
}
@Override
public Texture getTexture(AbsFace face) {
return (face == AbsFace.POS_Z) ? topTexture : sideTexture;
public Texture getTexture(RelFace face) {
return (face == RelFace.UP) ? topTexture : sideTexture;
}
@Override
public boolean isOpaque(AbsFace face) {
return face == AbsFace.POS_Z;
public boolean isOpaque(RelFace face) {
return face == RelFace.UP;
}
}

View File

@ -30,14 +30,7 @@ public class TestGravityModel extends GravityModel {
@Override
protected void doGetGravity(Vec3 pos, Vec3 output) {
output.set(pos);
if (output.length() < 10) {
output.set(0);
return;
}
output.normalize().mul(-9.8f);
output.set(0, 0, -9.8f);
}
@Override