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.ChunkData;
import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.generic.GenericChunk;
import ru.windcorp.progressia.common.world.rels.AbsFace; 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.TileDataStack;
public class ChunkRender public class ChunkRender
@ -56,6 +58,11 @@ public class ChunkRender
return getData().getPosition(); return getData().getPosition();
} }
@Override
public AbsFace getUp() {
return getData().getUp();
}
@Override @Override
public BlockRender getBlock(Vec3i posInChunk) { public BlockRender getBlock(Vec3i posInChunk) {
return BlockRenderRegistry.getInstance().get( return BlockRenderRegistry.getInstance().get(
@ -64,12 +71,12 @@ public class ChunkRender
} }
@Override @Override
public TileRenderStack getTiles(Vec3i blockInChunk, AbsFace face) { public TileRenderStack getTiles(Vec3i blockInChunk, BlockFace face) {
return getTileStackWrapper(getData().getTiles(blockInChunk, face)); return getTileStackWrapper(getData().getTiles(blockInChunk, face));
} }
@Override @Override
public boolean hasTiles(Vec3i blockInChunk, AbsFace face) { public boolean hasTiles(Vec3i blockInChunk, BlockFace face) {
return getData().hasTiles(blockInChunk, face); return getData().hasTiles(blockInChunk, face);
} }
@ -119,7 +126,7 @@ public class ChunkRender
} }
@Override @Override
public AbsFace getFace() { public RelFace getFace() {
return parent.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.TileRenderNone;
import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.client.world.tile.TileRenderStack;
import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.rels.RelRelation;
public class ChunkRenderModel implements Renderable { public class ChunkRenderModel implements Renderable {
@ -53,11 +54,15 @@ public class ChunkRenderModel implements Renderable {
public void render(ShapeRenderHelper renderer) { public void render(ShapeRenderHelper renderer) {
if (model == null) return; if (model == null) return;
float offset = ChunkData.BLOCKS_PER_CHUNK / 2 - 0.5f;
renderer.pushTransform().translate( renderer.pushTransform().translate(
chunk.getX() * ChunkData.BLOCKS_PER_CHUNK, chunk.getX() * ChunkData.BLOCKS_PER_CHUNK,
chunk.getY() * ChunkData.BLOCKS_PER_CHUNK, chunk.getY() * ChunkData.BLOCKS_PER_CHUNK,
chunk.getZ() * 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); model.render(renderer);
@ -71,8 +76,8 @@ public class ChunkRenderModel implements Renderable {
optimizers.forEach(ChunkRenderOptimizer::startRender); optimizers.forEach(ChunkRenderOptimizer::startRender);
chunk.forEachBiC(blockInChunk -> { chunk.forEachBiC(relBlockInChunk -> {
processBlockAndTiles(blockInChunk, sink); processBlockAndTiles(relBlockInChunk, sink);
}); });
for (ChunkRenderOptimizer optimizer : optimizers) { for (ChunkRenderOptimizer optimizer : optimizers) {
@ -96,16 +101,16 @@ public class ChunkRenderModel implements Renderable {
} }
} }
private void processBlockAndTiles(Vec3i blockInChunk, Builder sink) { private void processBlockAndTiles(Vec3i relBlockInChunk, Builder sink) {
processBlock(blockInChunk, sink); processBlock(relBlockInChunk, sink);
for (AbsFace face : AbsFace.getFaces()) { for (RelFace face : RelFace.getFaces()) {
processTileStack(blockInChunk, face, sink); processTileStack(relBlockInChunk, face, sink);
} }
} }
private void processBlock(Vec3i blockInChunk, Builder sink) { private void processBlock(Vec3i relBlockInChunk, Builder sink) {
BlockRender block = chunk.getBlock(blockInChunk); BlockRender block = chunk.getBlockRel(relBlockInChunk);
if (block instanceof BlockRenderNone) { if (block instanceof BlockRenderNone) {
return; return;
@ -113,48 +118,48 @@ public class ChunkRenderModel implements Renderable {
if (block.needsOwnRenderable()) { if (block.needsOwnRenderable()) {
sink.addPart( sink.addPart(
block.createRenderable(chunk.getData(), blockInChunk), block.createRenderable(chunk.getData(), relBlockInChunk),
new Mat4().identity().translate(blockInChunk.x, blockInChunk.y, blockInChunk.z) 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) { for (ChunkRenderOptimizer optimizer : optimizers) {
optimizer.addBlock(block, blockInChunk); optimizer.addBlock(block, relBlockInChunk);
} }
} }
private void processTileStack(Vec3i blockInChunk, AbsFace face, Builder sink) { private void processTileStack(Vec3i relBlockInChunk, RelFace face, Builder sink) {
TileRenderStack trs = chunk.getTilesOrNull(blockInChunk, face); TileRenderStack trs = chunk.getTilesOrNullRel(relBlockInChunk, face);
if (trs == null || trs.isEmpty()) { if (trs == null || trs.isEmpty()) {
return; 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) { if (tile instanceof TileRenderNone) {
return; return;
} }
if (tile.needsOwnRenderable()) { if (tile.needsOwnRenderable()) {
sink.addPart( sink.addPart(
tile.createRenderable(chunk.getData(), blockInChunk, face), tile.createRenderable(chunk.getData(), relBlockInChunk, face),
new Mat4().identity().translate(blockInChunk.x, blockInChunk.y, blockInChunk.z) 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) { 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.ChunkDataListener;
import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.rels.AbsFace; 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.TileData;
class ChunkUpdateListener implements ChunkDataListener { class ChunkUpdateListener implements ChunkDataListener {
@ -57,7 +58,7 @@ class ChunkUpdateListener implements ChunkDataListener {
public void onChunkTilesChanged( public void onChunkTilesChanged(
ChunkData chunk, ChunkData chunk,
Vec3i blockInChunk, Vec3i blockInChunk,
AbsFace face, RelFace face,
TileData tile, TileData tile,
boolean wasAdded boolean wasAdded
) { ) {

View File

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

View File

@ -19,27 +19,27 @@
package ru.windcorp.progressia.client.world.block; package ru.windcorp.progressia.client.world.block;
import ru.windcorp.progressia.client.graphics.texture.Texture; 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 class BlockRenderOpaqueCube extends BlockRenderTexturedCube {
public BlockRenderOpaqueCube( public BlockRenderOpaqueCube(
String id, String id,
Texture posZTexture, Texture topTexture,
Texture negZTexture, Texture bottomTexture,
Texture posXTexture, Texture northTexture,
Texture negXTexture, Texture southTexture,
Texture negYTexture, Texture westTexture,
Texture posYTexture Texture eastTexture
) { ) {
super( super(
id, id,
posZTexture, topTexture,
negZTexture, bottomTexture,
posXTexture, northTexture,
negXTexture, southTexture,
negYTexture, westTexture,
posYTexture 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 @Override
public boolean isOpaque(AbsFace face) { public boolean isOpaque(RelFace face) {
return true; 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 static ru.windcorp.progressia.common.world.rels.AbsFace.*;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; 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.util.Vectors;
import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
public abstract class BlockRenderTexturedCube public abstract class BlockRenderTexturedCube
extends BlockRender extends BlockRender
implements BlockOptimizedSurface { implements BlockOptimizedSurface {
private final Map<AbsFace, Texture> textures = new HashMap<>(); private final Map<RelFace, Texture> textures;
public BlockRenderTexturedCube( public BlockRenderTexturedCube(
String id, String id,
Texture posZTexture, Texture topTexture,
Texture negZTexture, Texture bottomTexture,
Texture posXTexture, Texture northTexture,
Texture negXTexture, Texture southTexture,
Texture negYTexture, Texture westTexture,
Texture posYTexture Texture eastTexture
) { ) {
super(id); super(id);
this.textures = RelFace.mapToFaces(topTexture, bottomTexture, northTexture, southTexture, westTexture, eastTexture);
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);
} }
public Texture getTexture(AbsFace blockFace) { public Texture getTexture(RelFace blockFace) {
return textures.get(blockFace); return textures.get(blockFace);
} }
public Vec4 getColorMultiplier(AbsFace blockFace) { public Vec4 getColorMultiplier(RelFace blockFace) {
return Colors.WHITE; return Colors.WHITE;
} }
@Override @Override
public final void getShapeParts( public final void getShapeParts(
ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, ChunkData chunk, Vec3i blockInChunk, RelFace blockFace,
boolean inner, boolean inner,
Consumer<ShapePart> output, Consumer<ShapePart> output,
Vec3 offset Vec3 offset
@ -84,7 +78,7 @@ public abstract class BlockRenderTexturedCube
} }
private ShapePart createFace( private ShapePart createFace(
ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, ChunkData chunk, Vec3i blockInChunk, RelFace blockFace,
boolean inner, boolean inner,
Vec3 offset Vec3 offset
) { ) {
@ -93,7 +87,7 @@ public abstract class BlockRenderTexturedCube
getTexture(blockFace), getTexture(blockFace),
getColorMultiplier(blockFace), getColorMultiplier(blockFace),
offset, offset,
blockFace, blockFace.resolve(AbsFace.POS_Z),
inner inner
); );
} }
@ -105,12 +99,12 @@ public abstract class BlockRenderTexturedCube
ShapePart[] faces = new ShapePart[BLOCK_FACE_COUNT + (opaque ? BLOCK_FACE_COUNT : 0)]; ShapePart[] faces = new ShapePart[BLOCK_FACE_COUNT + (opaque ? BLOCK_FACE_COUNT : 0)];
for (int i = 0; i < BLOCK_FACE_COUNT; ++i) { 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) { if (!opaque) {
for (int i = 0; i < BLOCK_FACE_COUNT; ++i) { 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; package ru.windcorp.progressia.client.world.block;
import ru.windcorp.progressia.client.graphics.texture.Texture; 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 class BlockRenderTransparentCube extends BlockRenderTexturedCube {
public BlockRenderTransparentCube( public BlockRenderTransparentCube(
String id, String id,
Texture posZTexture, Texture topTexture,
Texture negZTexture, Texture bottomTexture,
Texture posXTexture, Texture northTexture,
Texture negXTexture, Texture southTexture,
Texture negYTexture, Texture westTexture,
Texture posYTexture Texture eastTexture
) { ) {
super( super(
id, id,
posZTexture, topTexture,
negZTexture, bottomTexture,
posXTexture, northTexture,
negXTexture, southTexture,
negYTexture, westTexture,
posYTexture 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 @Override
public boolean isOpaque(AbsFace face) { public boolean isOpaque(RelFace face) {
return false; 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.block.BlockRender;
import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.client.world.tile.TileRender;
import ru.windcorp.progressia.common.util.namespaces.Namespaced; 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 * 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 * tiles. An example of a CRO is {@link ChunkRenderOptimizerSurface}: it removes
* block surfaces and tiles that it knows cannot be seen, thus significantly * block surfaces and tiles that it knows cannot be seen, thus significantly
* reducing total polygon count. * 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> * <h3>CRO lifecycle</h3>
* A CRO instance is created by {@link ChunkRenderOptimizerRegistry}. It may * A CRO instance is created by {@link ChunkRenderOptimizerRegistry}. It may
* then be used to work on multiple chunks sequentially. Each chunk is processed * 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> * instance.</li>
* <li>{@link #startRender()} is invoked. The CRO must reset its state.</li> * <li>{@link #startRender()} is invoked. The CRO must reset its state.</li>
* <li>{@link #addBlock(BlockRender, Vec3i)} and * <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 * tile that this CRO should optimize. {@code addTile} specifies tiles in order
* of ascension within a tile stack.</li> * of ascension within a tile stack.</li>
* <li>{@link #endRender()} is invoked. The CRO may perform any pending * <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 * method is only invoked once per block. This method is not necessarily
* invoked for each block. * invoked for each block.
* *
* @param block a {@link BlockRender} instance describing the block. * @param block a {@link BlockRender} instance describing the
* It corresponds to * block.
* {@code getChunk().getBlock(blockInChunk)}. * It corresponds to
* @param blockInChunk the position of the block * {@code getChunk().getBlock(blockInChunk)}.
* @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 * Requests that this CRO processes the provided tile. This method may only
@ -112,11 +119,12 @@ public abstract class ChunkRenderOptimizer extends Namespaced {
* invoked for each tile. When multiple tiles in a tile stack are requested, * invoked for each tile. When multiple tiles in a tile stack are requested,
* this method is invoked for lower tiles first. * this method is invoked for lower tiles first.
* *
* @param tile a {@link BlockRender} instance describing the tile * @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
* @param blockFace the face that the tile belongs to * 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 * 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.client.world.tile.TileRender;
import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.RelFace;
public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
@ -56,20 +56,23 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
* surface. The coordinates of the face vertices must be in chunk * surface. The coordinates of the face vertices must be in chunk
* coordinate system. * coordinate system.
* *
* @param chunk the chunk that contains the requested face * @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 blockFace the requested face
* @param inner whether this face should be visible from inside * @param inner whether this face should be visible from
* ({@code true}) or outside ({@code false}) * inside
* @param output a consumer that the created shape parts must be * ({@code true}) or outside ({@code false})
* given to * @param output a consumer that the created shape parts must
* @param offset an additional offset that must be applied to all * be
* vertices * given to
* @param offset an additional offset that must be applied to
* all
* vertices
*/ */
void getShapeParts( void getShapeParts(
ChunkData chunk, ChunkData chunk,
Vec3i blockInChunk, Vec3i relBlockInChunk,
AbsFace blockFace, RelFace blockFace,
boolean inner, boolean inner,
Consumer<ShapePart> output, Consumer<ShapePart> output,
Vec3 offset /* kostyl 156% */ Vec3 offset /* kostyl 156% */
@ -77,14 +80,14 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
/** /**
* Returns the opacity of the surface identified by the provided * Returns the opacity of the surface identified by the provided
* {@link AbsFace}. * {@link RelFace}.
* Opaque surfaces prevent surfaces behind them from being included in * Opaque surfaces prevent surfaces behind them from being included in
* chunk models. * chunk models.
* *
* @param blockFace the face to query * @param blockFace the face to query
* @return {@code true} iff the surface is opaque. * @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 @Override
public void addBlock(BlockRender block, Vec3i pos) { public void addBlock(BlockRender block, Vec3i relBlockInChunk) {
if (!(block instanceof BlockOptimizedSurface)) if (!(block instanceof BlockOptimizedSurface))
return; return;
BlockOptimizedSurface bos = (BlockOptimizedSurface) block; BlockOptimizedSurface bos = (BlockOptimizedSurface) block;
addBlock(pos, bos); addBlock(relBlockInChunk, bos);
} }
@Override @Override
public void addTile(TileRender tile, Vec3i pos, AbsFace face) { public void addTile(TileRender tile, Vec3i relBlockInChunk, RelFace face) {
if (!(tile instanceof TileOptimizedSurface)) if (!(tile instanceof TileOptimizedSurface))
return; return;
TileOptimizedSurface tos = (TileOptimizedSurface) tile; TileOptimizedSurface tos = (TileOptimizedSurface) tile;
addTile(pos, face, tos); addTile(relBlockInChunk, face, tos);
} }
protected void addBlock(Vec3i pos, BlockOptimizedSurface block) { private void addBlock(Vec3i relBlockInChunk, BlockOptimizedSurface block) {
getBlock(pos).block = block; getBlock(relBlockInChunk).block = block;
} }
private void addTile(Vec3i pos, AbsFace face, TileOptimizedSurface tile) { private void addTile(Vec3i relBlockInChunk, RelFace face, TileOptimizedSurface tile) {
FaceInfo faceInfo = getFace(pos, face); FaceInfo faceInfo = getFace(relBlockInChunk, face);
int index = faceInfo.tileCount; int index = faceInfo.tileCount;
faceInfo.tileCount++; faceInfo.tileCount++;
@ -197,12 +200,12 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
} }
} }
protected BlockInfo getBlock(Vec3i cursor) { protected BlockInfo getBlock(Vec3i relBlockInChunk) {
return data[cursor.x][cursor.y][cursor.z]; return data[relBlockInChunk.x][relBlockInChunk.y][relBlockInChunk.z];
} }
protected FaceInfo getFace(Vec3i cursor, AbsFace face) { protected FaceInfo getFace(Vec3i relBlockInChunk, RelFace face) {
return getBlock(cursor).faces[face.getId()]; return getBlock(relBlockInChunk).faces[face.getId()];
} }
@Override @Override
@ -211,17 +214,12 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3 BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3
); );
Vec3i cursor = new Vec3i();
Consumer<ShapePart> consumer = shapeParts::add; Consumer<ShapePart> consumer = shapeParts::add;
for (cursor.x = 0; cursor.x < BLOCKS_PER_CHUNK; ++cursor.x) { chunk.forEachBiC(relBlockInChunk -> {
for (cursor.y = 0; cursor.y < BLOCKS_PER_CHUNK; ++cursor.y) { processInnerFaces(relBlockInChunk, consumer);
for (cursor.z = 0; cursor.z < BLOCKS_PER_CHUNK; ++cursor.z) { processOuterFaces(relBlockInChunk, consumer);
processInnerFaces(cursor, consumer); });
processOuterFaces(cursor, consumer);
}
}
}
if (shapeParts.isEmpty()) { if (shapeParts.isEmpty()) {
return null; return null;
@ -235,25 +233,25 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
} }
private void processOuterFaces( private void processOuterFaces(
Vec3i blockInChunk, Vec3i relBlockInChunk,
Consumer<ShapePart> output Consumer<ShapePart> output
) { ) {
for (AbsFace blockFace : AbsFace.getFaces()) { for (RelFace blockFace : RelFace.getFaces()) {
processOuterFace(blockInChunk, blockFace, output); processOuterFace(relBlockInChunk, blockFace, output);
} }
} }
private void processOuterFace(Vec3i blockInChunk, AbsFace blockFace, Consumer<ShapePart> output) { private void processOuterFace(Vec3i relBlockInChunk, RelFace blockFace, Consumer<ShapePart> output) {
if (!shouldRenderOuterFace(blockInChunk, blockFace)) if (!shouldRenderOuterFace(relBlockInChunk, blockFace))
return; return;
FaceInfo info = getFace(blockInChunk, blockFace); FaceInfo info = getFace(relBlockInChunk, blockFace);
if (info.tileCount == 0 && info.block.block == null) if (info.tileCount == 0 && info.block.block == null)
return; return;
Vec3 faceOrigin = new Vec3(blockInChunk.x, blockInChunk.y, blockInChunk.z); Vec3 faceOrigin = new Vec3(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z);
Vec3 offset = new Vec3(blockFace.getFloatVector()).mul(OVERLAY_OFFSET); Vec3 offset = new Vec3(blockFace.getRelFloatVector()).mul(OVERLAY_OFFSET);
for ( for (
int layer = info.topOpaqueSurface; int layer = info.topOpaqueSurface;
@ -264,32 +262,29 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
if (surface == null) if (surface == null)
continue; // layer may be BLOCK_LAYER, then block may be 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); faceOrigin.add(offset);
} }
} }
private void processInnerFaces( private void processInnerFaces(Vec3i relBlockInChunk, Consumer<ShapePart> output) {
Vec3i blockInChunk, for (RelFace blockFace : RelFace.getFaces()) {
Consumer<ShapePart> output processInnerFace(relBlockInChunk, blockFace, output);
) {
for (AbsFace blockFace : AbsFace.getFaces()) {
processInnerFace(blockInChunk, blockFace, output);
} }
} }
private void processInnerFace(Vec3i blockInChunk, AbsFace blockFace, Consumer<ShapePart> output) { private void processInnerFace(Vec3i relBlockInChunk, RelFace blockFace, Consumer<ShapePart> output) {
if (!shouldRenderInnerFace(blockInChunk, blockFace)) if (!shouldRenderInnerFace(relBlockInChunk, blockFace))
return; return;
FaceInfo info = getFace(blockInChunk, blockFace); FaceInfo info = getFace(relBlockInChunk, blockFace);
if (info.tileCount == 0 && info.block.block == null) if (info.tileCount == 0 && info.block.block == null)
return; return;
Vec3 faceOrigin = new Vec3(blockInChunk.x, blockInChunk.y, blockInChunk.z); Vec3 faceOrigin = new Vec3(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z);
Vec3 offset = new Vec3(blockFace.getFloatVector()).mul(OVERLAY_OFFSET); Vec3 offset = new Vec3(blockFace.getRelFloatVector()).mul(OVERLAY_OFFSET);
for ( for (
int layer = FaceInfo.BLOCK_LAYER; int layer = FaceInfo.BLOCK_LAYER;
@ -300,35 +295,35 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
if (surface == null) if (surface == null)
continue; // layer may be BLOCK_LAYER, then block may be 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); faceOrigin.add(offset);
} }
} }
private boolean shouldRenderOuterFace(Vec3i blockInChunk, AbsFace face) { private boolean shouldRenderOuterFace(Vec3i relBlockInChunk, RelFace face) {
blockInChunk.add(face.getVector()); relBlockInChunk.add(face.getRelVector());
try { try {
return shouldRenderWhenFacing(blockInChunk, face); return shouldRenderWhenFacing(relBlockInChunk, face);
} finally { } finally {
blockInChunk.sub(face.getVector()); relBlockInChunk.sub(face.getRelVector());
} }
} }
private boolean shouldRenderInnerFace(Vec3i blockInChunk, AbsFace face) { private boolean shouldRenderInnerFace(Vec3i relBlockInChunk, RelFace face) {
return shouldRenderWhenFacing(blockInChunk, face); return shouldRenderWhenFacing(relBlockInChunk, face);
} }
private boolean shouldRenderWhenFacing(Vec3i blockInChunk, AbsFace face) { private boolean shouldRenderWhenFacing(Vec3i relBlockInChunk, RelFace face) {
if (chunk.containsBiC(blockInChunk)) { if (chunk.containsBiC(relBlockInChunk)) {
return shouldRenderWhenFacingLocal(blockInChunk, face); return shouldRenderWhenFacingLocal(relBlockInChunk, face);
} else { } else {
return shouldRenderWhenFacingNeighbor(blockInChunk, face); return shouldRenderWhenFacingNeighbor(relBlockInChunk, face);
} }
} }
private boolean shouldRenderWhenFacingLocal(Vec3i blockInChunk, AbsFace face) { private boolean shouldRenderWhenFacingLocal(Vec3i relBlockInChunk, RelFace face) {
BlockOptimizedSurface block = getBlock(blockInChunk).block; BlockOptimizedSurface block = getBlock(relBlockInChunk).block;
if (block == null) { if (block == null) {
return true; return true;
@ -340,36 +335,37 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
return true; return true;
} }
private boolean shouldRenderWhenFacingNeighbor(Vec3i blockInLocalChunk, AbsFace face) { private boolean shouldRenderWhenFacingNeighbor(Vec3i relBlockInLocalChunk, RelFace face) {
Vec3i blockInChunk = Vectors.grab3i().set(blockInLocalChunk.x, blockInLocalChunk.y, blockInLocalChunk.z); Vec3i blockInChunk = Vectors.grab3i();
chunk.resolve(relBlockInLocalChunk, blockInChunk);
Vec3i chunkPos = Vectors.grab3i().set(chunk.getX(), chunk.getY(), chunk.getZ()); Vec3i chunkPos = Vectors.grab3i().set(chunk.getX(), chunk.getY(), chunk.getZ());
try { try {
// Determine blockInChunk and chunkPos // Determine blockInChunk and chunkPos
if (blockInLocalChunk.x == -1) { if (blockInChunk.x == -1) {
blockInChunk.x = BLOCKS_PER_CHUNK - 1; blockInChunk.x = BLOCKS_PER_CHUNK - 1;
chunkPos.x -= 1; chunkPos.x -= 1;
} else if (blockInLocalChunk.x == BLOCKS_PER_CHUNK) { } else if (blockInChunk.x == BLOCKS_PER_CHUNK) {
blockInChunk.x = 0; blockInChunk.x = 0;
chunkPos.x += 1; chunkPos.x += 1;
} else if (blockInLocalChunk.y == -1) { } else if (blockInChunk.y == -1) {
blockInChunk.y = BLOCKS_PER_CHUNK - 1; blockInChunk.y = BLOCKS_PER_CHUNK - 1;
chunkPos.y -= 1; chunkPos.y -= 1;
} else if (blockInLocalChunk.y == BLOCKS_PER_CHUNK) { } else if (blockInChunk.y == BLOCKS_PER_CHUNK) {
blockInChunk.y = 0; blockInChunk.y = 0;
chunkPos.y += 1; chunkPos.y += 1;
} else if (blockInLocalChunk.z == -1) { } else if (blockInChunk.z == -1) {
blockInChunk.z = BLOCKS_PER_CHUNK - 1; blockInChunk.z = BLOCKS_PER_CHUNK - 1;
chunkPos.z -= 1; chunkPos.z -= 1;
} else if (blockInLocalChunk.z == BLOCKS_PER_CHUNK) { } else if (blockInChunk.z == BLOCKS_PER_CHUNK) {
blockInChunk.z = 0; blockInChunk.z = 0;
chunkPos.z += 1; chunkPos.z += 1;
} else { } else {
throw new AssertionError( throw new AssertionError(
"Requested incorrent neighbor (" "Requested incorrent neighbor ("
+ blockInLocalChunk.x + "; " + relBlockInLocalChunk.x + "; "
+ blockInLocalChunk.y + "; " + relBlockInLocalChunk.y + "; "
+ blockInLocalChunk.z + ")" + relBlockInLocalChunk.z + ")"
); );
} }
@ -382,8 +378,11 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer {
return true; return true;
BlockOptimizedSurface bos = (BlockOptimizedSurface) block; BlockOptimizedSurface bos = (BlockOptimizedSurface) block;
if (!bos.isOpaque(face)) RelFace rotatedFace = face.rotate(this.chunk.getUp(), chunk.getUp());
if (!bos.isOpaque(rotatedFace)) {
return true; return true;
}
return false; return false;

View File

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

View File

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

View File

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

View File

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

View File

@ -20,7 +20,7 @@ package ru.windcorp.progressia.common.world;
import glm.vec._3.i.Vec3i; import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.block.BlockData; 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.common.world.tile.TileData;
public interface ChunkDataListener { public interface ChunkDataListener {
@ -55,7 +55,7 @@ public interface ChunkDataListener {
default void onChunkTilesChanged( default void onChunkTilesChanged(
ChunkData chunk, ChunkData chunk,
Vec3i blockInChunk, Vec3i blockInChunk,
AbsFace face, RelFace face,
TileData tile, TileData tile,
boolean wasAdded 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.util.Vectors;
import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.rels.AbsFace; 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>> { 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(); Vec3i getPosition();
AbsFace getUp();
B getBlock(Vec3i blockInChunk); 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() { default int getX() {
return getPosition().x; 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)) { if (hasTiles(blockInChunk, face)) {
return getTiles(blockInChunk, face); return getTiles(blockInChunk, face);
} }
@ -190,4 +235,21 @@ public interface GenericChunk<Self extends GenericChunk<Self, B, T, TS>, B exten
return null; 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 glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.Coordinates; 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>> public abstract class GenericTileStack<Self extends GenericTileStack<Self, T, C>, T extends GenericTile, C extends GenericChunk<C, ?, T, Self>>
extends AbstractList<T> extends AbstractList<T>
@ -41,7 +41,7 @@ public abstract class GenericTileStack<Self extends GenericTileStack<Self, T, C>
public abstract C getChunk(); public abstract C getChunk();
public abstract AbsFace getFace(); public abstract RelFace getFace();
public Vec3i getBlockInWorld(Vec3i output) { public Vec3i getBlockInWorld(Vec3i output) {
// This is safe // 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.util.Vectors;
import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.rels.AbsFace; 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> { 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; return result;
} }
default AbsFace getUp(Vec3i blockInWorld) {
return getChunkByBlock(blockInWorld).getUp();
}
default B getBlock(Vec3i blockInWorld) { default B getBlock(Vec3i blockInWorld) {
Vec3i v = Vectors.grab3i(); Vec3i v = Vectors.grab3i();
B result; B result;
@ -63,7 +68,7 @@ public interface GenericWorld<B extends GenericBlock, T extends GenericTile, TS
return result; return result;
} }
default TS getTiles(Vec3i blockInWorld, AbsFace face) { default TS getTiles(Vec3i blockInWorld, BlockFace face) {
Vec3i v = Vectors.grab3i(); Vec3i v = Vectors.grab3i();
TS result; TS result;
@ -78,7 +83,7 @@ public interface GenericWorld<B extends GenericBlock, T extends GenericTile, TS
return result; return result;
} }
default TS getTilesOrNull(Vec3i blockInWorld, AbsFace face) { default TS getTilesOrNull(Vec3i blockInWorld, BlockFace face) {
Vec3i v = Vectors.grab3i(); Vec3i v = Vectors.grab3i();
TS result; TS result;
@ -93,7 +98,7 @@ public interface GenericWorld<B extends GenericBlock, T extends GenericTile, TS
return result; return result;
} }
default boolean hasTiles(Vec3i blockInWorld, AbsFace face) { default boolean hasTiles(Vec3i blockInWorld, BlockFace face) {
Vec3i v = Vectors.grab3i(); Vec3i v = Vectors.grab3i();
boolean result; boolean result;
@ -108,7 +113,7 @@ public interface GenericWorld<B extends GenericBlock, T extends GenericTile, TS
return result; 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); TS stack = getTilesOrNull(blockInWorld, face);
if (stack == null || stack.size() <= layer) if (stack == null || stack.size() <= layer)
return null; return null;

View File

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

View File

@ -41,6 +41,18 @@ public class AbsRelation extends BlockRelation {
this(vector.x, vector.y, vector.z); 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 @Override
public AbsRelation resolve(AbsFace up) { public AbsRelation resolve(AbsFace up) {
return this; 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; import glm.vec._3.i.Vec3i;
public class RelFace extends RelRelation { public class RelFace extends RelRelation implements BlockFace {
// @formatter:off // @formatter:off
public static final RelFace public static final RelFace
@ -76,7 +76,7 @@ public class RelFace extends RelRelation {
private RelFace counterFace; private RelFace counterFace;
private RelFace(int x, int y, int z, String name) { private RelFace(int x, int y, int z, String name) {
super(x, y, z, true); super(x, y, z, false);
this.id = nextId++; this.id = nextId++;
this.name = name; this.name = name;
} }
@ -85,6 +85,24 @@ public class RelFace extends RelRelation {
return name; 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 * @return the id
*/ */
@ -97,7 +115,7 @@ public class RelFace extends RelRelation {
} }
public RelFace getCounterAndMoveCursor(Vec3i cursor) { public RelFace getCounterAndMoveCursor(Vec3i cursor) {
cursor.add(getVector()); cursor.add(getRelVector());
return counterFace; return counterFace;
} }

View File

@ -19,8 +19,12 @@ package ru.windcorp.progressia.common.world.rels;
import java.util.Map; 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 glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.util.VectorUtil.SignedAxis; import ru.windcorp.progressia.common.util.VectorUtil.SignedAxis;
import static 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 westDestination;
private final SignedAxis upDestination; 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.northDestination = northDestination;
this.westDestination = westDestination; this.westDestination = westDestination;
this.upDestination = upDestination; 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) { public Vec3i apply(Vec3i output, Vec3i input) {
if (output == null) { if (output == null) {
return output; output = new Vec3i();
} }
set(output, input.x, northDestination); int inX = input.x, inY = input.y, inZ = input.z;
set(output, input.y, westDestination);
set(output, input.z, upDestination); set(output, inX, northDestination);
set(output, inY, westDestination);
set(output, inZ, upDestination);
return output; return output;
} }
@ -56,6 +104,24 @@ public class RelRelation extends BlockRelation {
private static void set(Vec3i output, int value, SignedAxis axis) { private static void set(Vec3i output, int value, SignedAxis axis) {
VectorUtil.set(output, axis.getAxis(), axis.isPositive() ? +value : -value); 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( 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 Vec3i vector = new Vec3i();
private final Vec3 floatVector = new Vec3();
private final Vec3 normalized = new Vec3();
private AbsRelation[] resolved = null; private AbsRelation[] resolved = null;
public RelRelation(int north, int west, int up) { public RelRelation(int north, int west, int up) {
this(north, west, up, false); 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) { protected RelRelation(int north, int west, int up, boolean precomputeAllResolutions) {
vector.set(north, west, up); vector.set(north, west, up);
floatVector.set(north, west, up);
normalized.set(north, west, up);
if (normalized.any()) {
normalized.normalize();
}
if (precomputeAllResolutions) { if (precomputeAllResolutions) {
for (AbsFace face : AbsFace.getFaces()) { 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) * @return the relative vector (northward, westward, upward)
*/ */
public Vec3i getVector() { public Vec3i getRelVector() {
return vector; return vector;
} }
public Vec3 getRelFloatVector() {
return floatVector;
}
public Vec3 getRelNormalized() {
return normalized;
}
public int getNorthward() { public int getNorthward() {
return vector.x; return vector.x;
} }
@ -129,12 +241,43 @@ public class RelRelation extends BlockRelation {
} }
private AbsRelation computeResolution(AbsFace up) { 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 @Override
protected Vec3i getSample() { protected Vec3i getSample() {
return getVector(); return getRelVector();
} }
} }

View File

@ -68,9 +68,9 @@ public class Server {
this.chunkManager = new ChunkManager(this); this.chunkManager = new ChunkManager(this);
this.entityManager = new EntityManager(this); this.entityManager = new EntityManager(this);
schedule(this::scheduleWorldTicks);
schedule(chunkManager::tick); schedule(chunkManager::tick);
schedule(entityManager::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.Coordinates;
import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.generic.GenericChunk;
import ru.windcorp.progressia.common.world.rels.AbsFace; 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.TileDataStack;
import ru.windcorp.progressia.common.world.tile.TileReference; import ru.windcorp.progressia.common.world.tile.TileReference;
import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.BlockLogic;
@ -67,6 +69,11 @@ public class ChunkLogic implements GenericChunk<ChunkLogic, BlockLogic, TileLogi
return getData().getPosition(); return getData().getPosition();
} }
@Override
public AbsFace getUp() {
return getData().getUp();
}
@Override @Override
public BlockLogic getBlock(Vec3i blockInChunk) { public BlockLogic getBlock(Vec3i blockInChunk) {
return BlockLogicRegistry.getInstance().get( return BlockLogicRegistry.getInstance().get(
@ -75,12 +82,12 @@ public class ChunkLogic implements GenericChunk<ChunkLogic, BlockLogic, TileLogi
} }
@Override @Override
public TileLogicStack getTiles(Vec3i blockInChunk, AbsFace face) { public TileLogicStack getTiles(Vec3i blockInChunk, BlockFace face) {
return getTileStackWrapper(getData().getTiles(blockInChunk, face)); return getTileStackWrapper(getData().getTiles(blockInChunk, face));
} }
@Override @Override
public boolean hasTiles(Vec3i blockInChunk, AbsFace face) { public boolean hasTiles(Vec3i blockInChunk, BlockFace face) {
return getData().hasTiles(blockInChunk, face); return getData().hasTiles(blockInChunk, face);
} }
@ -149,7 +156,7 @@ public class ChunkLogic implements GenericChunk<ChunkLogic, BlockLogic, TileLogi
} }
@Override @Override
public AbsFace getFace() { public RelFace getFace() {
return parent.getFace(); return parent.getFace();
} }

View File

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

View File

@ -21,7 +21,7 @@ package ru.windcorp.progressia.server.world;
import glm.vec._3.i.Vec3i; import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.world.entity.EntityData; 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.Server;
import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.BlockLogic;
import ru.windcorp.progressia.server.world.block.BlockTickContext; 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); TileLogic tile = world.getTile(blockInWorld, face, layer);
if (!(tile instanceof TickableTile)) if (!(tile instanceof TickableTile)) {
return; return;
}
TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face) TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face)
.withLayer(layer); .withLayer(layer);
tickTile((TickableTile) tile, tickContext); 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() TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build()
.forEachTile(context -> { .forEachTile(context -> {
TileLogic tile = context.getTile(); 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); TileLogic tile = world.getTile(blockInWorld, face, layer);
if (!(tile instanceof UpdateableTile)) if (!(tile instanceof UpdateableTile)) {
return; return;
}
TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face) TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face)
.withLayer(layer); .withLayer(layer);
updateTile((UpdateableTile) tile, tickContext); 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() TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build()
.forEachTile(context -> { .forEachTile(context -> {
TileLogic tile = context.getTile(); 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.ChunkData;
import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.generic.GenericTileStack; 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.TileDataStack;
import ru.windcorp.progressia.common.world.tile.TileReference; import ru.windcorp.progressia.common.world.tile.TileReference;
import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.Server;
@ -126,7 +127,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
} }
public static interface Block extends Builder { public static interface Block extends Builder {
Builder.TileStack withFace(AbsFace face); Builder.TileStack withFace(BlockFace face);
} }
public static interface TileStack extends Builder { public static interface TileStack extends Builder {
@ -148,7 +149,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
protected Server server; protected Server server;
protected final Vec3i chunk = new Vec3i(); protected final Vec3i chunk = new Vec3i();
protected final Vec3i blockInWorld = new Vec3i(); protected final Vec3i blockInWorld = new Vec3i();
protected AbsFace face; protected RelFace face;
protected int layer; protected int layer;
protected Role role = Role.NONE; protected Role role = Role.NONE;
@ -188,7 +189,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
} }
@Override @Override
public AbsFace getFace() { public RelFace getFace() {
checkContextState(Role.TILE_STACK); checkContextState(Role.TILE_STACK);
return this.face; return this.face;
} }
@ -261,8 +262,9 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
public TileStack withTS(GenericTileStack<?, ?, ?> tileStack) { public TileStack withTS(GenericTileStack<?, ?, ?> tileStack) {
Objects.requireNonNull(tileStack, "tileStack"); Objects.requireNonNull(tileStack, "tileStack");
return withBlock(tileStack.getBlockInWorld(this.blockInWorld)).withFace(tileStack.getFace()); return withBlock(
// ^^^^^^^^^^^^^^^^^ This is safe tileStack.getBlockInWorld(this.blockInWorld) // This is safe
).withFace(tileStack.getFace());
} }
@Override @Override
@ -277,11 +279,11 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
} }
@Override @Override
public TileStack withFace(AbsFace face) { public TileStack withFace(BlockFace face) {
Objects.requireNonNull(face, "face"); Objects.requireNonNull(face, "face");
checkBuilderState(Role.BLOCK); checkBuilderState(Role.BLOCK);
this.face = face; this.face = face.relativize(server.getWorld().getChunk(chunk).getUp());
this.role = Role.TILE_STACK; this.role = Role.TILE_STACK;
return this; return this;
@ -339,12 +341,12 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
@Override @Override
public void forEachFace(Consumer<TSTickContext> action) { public void forEachFace(Consumer<TSTickContext> action) {
checkContextState(Role.BLOCK); checkContextState(Role.BLOCK);
AbsFace previousFace = this.face; RelFace previousFace = this.face;
Role previousRole = this.role; Role previousRole = this.role;
this.role = Role.TILE_STACK; this.role = Role.TILE_STACK;
for (int i = 0; i < AbsFace.BLOCK_FACE_COUNT; ++i) { for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) {
this.face = AbsFace.getFaces().get(i); this.face = RelFace.getFaces().get(i);
action.accept(this); action.accept(this);
} }
@ -393,11 +395,13 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
Objects.requireNonNull(action, "action"); Objects.requireNonNull(action, "action");
checkContextState(Role.TILE_STACK); 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(); this.face = this.face.getCounter();
R result = action.apply(this); R result = action.apply(this);
this.face = this.face.getCounter(); this.face = this.face.getCounter();
this.blockInWorld.sub(this.face.getVector()); this.blockInWorld.sub(vector);
return result; return result;
} }
@ -407,11 +411,13 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont
Objects.requireNonNull(action, "action"); Objects.requireNonNull(action, "action");
checkContextState(Role.TILE_STACK); 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(); this.face = this.face.getCounter();
action.accept(this); action.accept(this);
this.face = this.face.getCounter(); 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.ChunkDataListener;
import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.block.BlockData; 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.common.world.tile.TileData;
import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.Server;
@ -49,7 +49,7 @@ public class UpdateTriggerer implements ChunkDataListener {
public void onChunkTilesChanged( public void onChunkTilesChanged(
ChunkData chunk, ChunkData chunk,
Vec3i blockInChunk, Vec3i blockInChunk,
AbsFace face, RelFace face,
TileData tile, TileData tile,
boolean wasAdded boolean wasAdded
) { ) {

View File

@ -39,13 +39,8 @@ import ru.windcorp.progressia.server.world.tile.TileLogic;
import ru.windcorp.progressia.server.world.tile.TileLogicStack; import ru.windcorp.progressia.server.world.tile.TileLogicStack;
public class WorldLogic public class WorldLogic
implements GenericWorld<BlockLogic, TileLogic, TileLogicStack, ChunkLogic, EntityData // not implements GenericWorld<BlockLogic, TileLogic, TileLogicStack, ChunkLogic, EntityData
// using // not using EntityLogic because it is stateless
// EntityLogic
// because
// it
// is
// stateless
> { > {
private final WorldData data; 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.util.namespaces.Namespaced;
import ru.windcorp.progressia.common.world.generic.GenericBlock; 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 { public class BlockLogic extends Namespaced implements GenericBlock {
@ -28,11 +28,11 @@ public class BlockLogic extends Namespaced implements GenericBlock {
super(id); super(id);
} }
public boolean isSolid(BlockTickContext context, AbsFace face) { public boolean isSolid(BlockTickContext context, RelFace face) {
return isSolid(face); return isSolid(face);
} }
public boolean isSolid(AbsFace face) { public boolean isSolid(RelFace face) {
return true; 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.Coordinates;
import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.rels.AbsFace; 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.ChunkTickContext;
import ru.windcorp.progressia.server.world.TickContextMutable; import ru.windcorp.progressia.server.world.TickContextMutable;
import ru.windcorp.progressia.server.world.tile.TSTickContext; 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(); return TickContextMutable.copyWorld(this).withBlock(getBlockInWorld().add_(direction)).build();
} }
default BlockTickContext getNeighbor(AbsRelation relation) { default BlockTickContext getNeighbor(BlockRelation relation) {
Objects.requireNonNull(relation, "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) { default <R> R evalNeighbor(Vec3i direction, Function<BlockTickContext, R> action) {
@ -78,10 +78,10 @@ public interface BlockTickContext extends ChunkTickContext {
return action.apply(getNeighbor(direction)); 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(action, "action");
Objects.requireNonNull(relation, "relation"); Objects.requireNonNull(relation, "relation");
return evalNeighbor(relation.getVector(), action); return evalNeighbor(relation.getVector(getChunkData().getUp()), action);
} }
default void forNeighbor(Vec3i direction, Consumer<BlockTickContext> 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(action, "action");
Objects.requireNonNull(relation, "relation"); 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.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.common.world.entity.EntityData; 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.TileData;
import ru.windcorp.progressia.common.world.tile.TileDataRegistry; import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.Server;
@ -64,19 +64,19 @@ public class WorldAccessor {
setBlock(blockInWorld, BlockDataRegistry.getInstance().get(id)); 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); 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); 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)); 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); 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); server.requestChange(change);
} }
@ -91,6 +91,7 @@ public class WorldAccessor {
public void tickBlock(Vec3i blockInWorld) { public void tickBlock(Vec3i blockInWorld) {
// TODO // TODO
System.err.println("WorldAccessor.tickBlock(Vec3i) NYI!");
} }
/** /**
@ -112,9 +113,9 @@ public class WorldAccessor {
* @param face * @param face
*/ */
// TODO rename to something meaningful // 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); TileTriggeredUpdate evaluation = cache.grab(TileTriggeredUpdate.class);
evaluation.init(blockInWorld, face); evaluation.init(blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld)));
server.requestEvaluation(evaluation); server.requestEvaluation(evaluation);
} }

View File

@ -23,7 +23,7 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.common.world.tile.TileDataStack;
import ru.windcorp.progressia.server.world.ChunkLogic; import ru.windcorp.progressia.server.world.ChunkLogic;
import ru.windcorp.progressia.server.world.TickContextMutable; import ru.windcorp.progressia.server.world.TickContextMutable;
@ -35,7 +35,7 @@ public interface TSTickContext extends BlockTickContext {
* Specifications * Specifications
*/ */
AbsFace getFace(); RelFace getFace();
/* /*
* Getters * Getters
@ -91,7 +91,7 @@ public interface TSTickContext extends BlockTickContext {
default TSTickContext getComplementary() { default TSTickContext getComplementary() {
return TickContextMutable.copyWorld(this) return TickContextMutable.copyWorld(this)
.withBlock(getBlockInWorld().add_(getFace().getVector())) .withBlock(getBlockInWorld().add_(getFace().getVector(getUp())))
.withFace(getFace().getCounter()) .withFace(getFace().getCounter())
.build(); .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.util.namespaces.Namespaced;
import ru.windcorp.progressia.common.world.generic.GenericTile; 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 { public class TileLogic extends Namespaced implements GenericTile {
@ -32,7 +32,7 @@ public class TileLogic extends Namespaced implements GenericTile {
return canOccupyFace(context.getFace()); return canOccupyFace(context.getFace());
} }
public boolean canOccupyFace(AbsFace face) { public boolean canOccupyFace(RelFace face) {
return true; return true;
} }

View File

@ -18,7 +18,7 @@
package ru.windcorp.progressia.test; 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.BlockLogic;
public class TestBlockLogicAir extends BlockLogic { public class TestBlockLogicAir extends BlockLogic {
@ -28,7 +28,7 @@ public class TestBlockLogicAir extends BlockLogic {
} }
@Override @Override
public boolean isSolid(AbsFace face) { public boolean isSolid(RelFace face) {
return false; return false;
} }

View File

@ -18,7 +18,7 @@
package ru.windcorp.progressia.test; 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.BlockLogic;
public class TestBlockLogicGlass extends BlockLogic { public class TestBlockLogicGlass extends BlockLogic {
@ -28,7 +28,7 @@ public class TestBlockLogicGlass extends BlockLogic {
} }
@Override @Override
public boolean isSolid(AbsFace face) { public boolean isSolid(RelFace face) {
return false; 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.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.common.world.io.ChunkCodec; 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.TileData;
import ru.windcorp.progressia.common.world.tile.TileDataRegistry; import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
@ -91,6 +91,9 @@ public class TestChunkCodec extends ChunkCodec {
TileData[] tilePalette = readTilePalette(input); TileData[] tilePalette = readTilePalette(input);
ChunkData chunk = new ChunkData(position, world); ChunkData chunk = new ChunkData(position, world);
assert chunk.getUp() == ru.windcorp.progressia.server.ServerState.getInstance().getWorld().getData().getChunk(position).getUp();
readBlocks(input, blockPalette, chunk); readBlocks(input, blockPalette, chunk);
readTiles(input, tilePalette, chunk); readTiles(input, tilePalette, chunk);
@ -138,7 +141,7 @@ public class TestChunkCodec extends ChunkCodec {
break; break;
bic.set(xOrEndMarker, input.readByte() & 0xFF, input.readByte() & 0xFF); 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; int tiles = input.readByte() & 0xFF;

View File

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

View File

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

View File

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

View File

@ -16,17 +16,18 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * 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.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 topTexture;
private final Texture sideTexture; private final Texture sideTexture;
public TileRenderGrass( public TestTileRenderGrass(
String id, String id,
Texture top, Texture top,
Texture side Texture side
@ -37,13 +38,13 @@ public class TileRenderGrass extends TileRenderSurface {
} }
@Override @Override
public Texture getTexture(AbsFace face) { public Texture getTexture(RelFace face) {
return (face == AbsFace.POS_Z) ? topTexture : sideTexture; return (face == RelFace.UP) ? topTexture : sideTexture;
} }
@Override @Override
public boolean isOpaque(AbsFace face) { public boolean isOpaque(RelFace face) {
return face == AbsFace.POS_Z; return face == RelFace.UP;
} }
} }

View File

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