Added TileLogic

This commit is contained in:
OLEGSHA 2020-08-31 20:39:35 +03:00
parent fcf5da731f
commit 068f229a45
18 changed files with 601 additions and 78 deletions

View File

@ -26,6 +26,8 @@ import ru.windcorp.progressia.server.comms.Client;
import ru.windcorp.progressia.server.comms.controls.ControlLogic;
import ru.windcorp.progressia.server.comms.controls.ControlLogicRegistry;
import ru.windcorp.progressia.server.world.block.*;
import ru.windcorp.progressia.server.world.tile.TileLogic;
import ru.windcorp.progressia.server.world.tile.TileLogicRegistry;
public class TestContent {
@ -64,15 +66,19 @@ public class TestContent {
private static void registerTiles() {
register(new TileData("Test", "Grass"));
register(new TileRenderGrass("Test", "Grass", getTileTexture("grass_top"), getTileTexture("grass_side")));
register(new TileLogic("Test", "Grass"));
register(new TileData("Test", "Stones"));
register(new TileRenderSimple("Test", "Stones", getTileTexture("stones")));
register(new TileLogic("Test", "Stones"));
register(new TileData("Test", "YellowFlowers"));
register(new TileRenderSimple("Test", "YellowFlowers", getTileTexture("yellow_flowers")));
register(new TileLogic("Test", "YellowFlowers"));
register(new TileData("Test", "Sand"));
register(new TileRenderSimple("Test", "Sand", getTileTexture("sand")));
register(new TileLogic("Test", "Sand"));
}
private static void regsiterControls() {
@ -117,8 +123,8 @@ public class TestContent {
BlockLogicRegistry.getInstance().register(x);
}
// private static void register(TileRender x) {
// TileLogicRegistry.getInstance().register(x);
// }
private static void register(TileLogic x) {
TileLogicRegistry.getInstance().register(x);
}
}

View File

@ -0,0 +1,22 @@
package ru.windcorp.progressia.client.world.tile;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.block.BlockFace;
public class TileLocation {
public final Vec3i pos = new Vec3i();
public BlockFace face;
public int layer;
public TileLocation() {
// Do nothing
}
public TileLocation(TileLocation src) {
this.pos.set(src.pos.x, src.pos.y, src.pos.z);
this.face = src.face;
this.layer = src.layer;
}
}

View File

@ -21,11 +21,13 @@ import static ru.windcorp.progressia.common.world.block.BlockFace.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import com.google.common.collect.Lists;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.client.world.tile.TileLocation;
import ru.windcorp.progressia.common.util.SizeLimitedList;
import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.util.Vectors;
@ -249,6 +251,34 @@ public class ChunkData {
action
);
}
/**
* Iterates over all tiles in this chunk. Tiles are referenced using their
* primary block (so that the face is
* {@linkplain BlockFace#isPrimary() primary}).
*
* @param action the action to perform. {@code TileLocation} refers to each
* tile using its primary block
*/
public void forEachTile(BiConsumer<TileLocation, TileData> action) {
TileLocation loc = new TileLocation();
forEachBlock(blockInChunk -> {
loc.pos.set(blockInChunk.x, blockInChunk.y, blockInChunk.z);
for (BlockFace face : BlockFace.getPrimaryFaces()) {
List<TileData> list = getTilesOrNull(blockInChunk, face);
if (list == null) continue;
loc.face = face;
for (loc.layer = 0; loc.layer < list.size(); ++loc.layer) {
TileData tile = list.get(loc.layer);
action.accept(loc, tile);
}
}
});
}
public int getX() {
return position.x;

View File

@ -2,43 +2,82 @@ package ru.windcorp.progressia.server.world;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.function.BiConsumer;
import com.google.common.collect.Lists;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.client.world.tile.TileLocation;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.block.BlockFace;
import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.server.world.block.BlockLogic;
import ru.windcorp.progressia.server.world.block.BlockLogicRegistry;
import ru.windcorp.progressia.server.world.block.Tickable;
import ru.windcorp.progressia.server.world.block.TickableBlock;
import ru.windcorp.progressia.server.world.tile.TickableTile;
import ru.windcorp.progressia.server.world.tile.TileLogic;
import ru.windcorp.progressia.server.world.tile.TileLogicRegistry;
public class ChunkLogic {
private final WorldLogic world;
private final ChunkData data;
private final Collection<Vec3i> ticking = new ArrayList<>();
private final Collection<Vec3i> tickingBlocks = new ArrayList<>();
private final Collection<TileLocation> tickingTiles = new ArrayList<>();
private final Map<List<TileData>, List<TileLogic>> tileLogicLists =
Collections.synchronizedMap(new WeakHashMap<>());
public ChunkLogic(WorldLogic world, ChunkData data) {
this.world = world;
this.data = data;
generateTickList();
generateTickLists();
}
private void generateTickList() {
private void generateTickLists() {
MutableBlockTickContext blockTickContext =
new MutableBlockTickContext();
MutableTileTickContext tileTickContext =
new MutableTileTickContext();
blockTickContext.setWorld(getWorld());
blockTickContext.setChunk(this);
tileTickContext.setWorld(getWorld());
tileTickContext.setChunk(this);
data.forEachBlock(blockInChunk -> {
BlockLogic block = getBlock(blockInChunk);
if (block instanceof Tickable) {
if (block instanceof TickableBlock) {
blockTickContext.setCoordsInChunk(blockInChunk);
if (((Tickable) block).doesTickRegularly(blockTickContext)) {
ticking.add(new Vec3i(blockInChunk));
if (((TickableBlock) block)
.doesTickRegularly(blockTickContext)
) {
tickingBlocks.add(new Vec3i(blockInChunk));
}
}
});
data.forEachTile((loc, tileData) -> {
TileLogic tile =
TileLogicRegistry.getInstance().get(tileData.getId());
if (tile instanceof TickableTile) {
tileTickContext.setCoordsInChunk(loc.pos);
tileTickContext.setFace(loc.face);
tileTickContext.setLayer(loc.layer);
if (((TickableTile) tile).doesTickRegularly(tileTickContext)) {
tickingTiles.add(new TileLocation(loc));
}
}
});
@ -53,19 +92,57 @@ public class ChunkLogic {
}
public boolean hasTickingBlocks() {
return ticking.isEmpty();
return !tickingBlocks.isEmpty();
}
public boolean hasTickingTiles() {
return !tickingTiles.isEmpty();
}
public void forEachTickingBlock(BiConsumer<Vec3i, BlockLogic> action) {
ticking.forEach(blockInChunk -> {
tickingBlocks.forEach(blockInChunk -> {
action.accept(blockInChunk, getBlock(blockInChunk));
});
}
public void forEachTickingTile(BiConsumer<TileLocation, TileLogic> action) {
tickingTiles.forEach(location -> {
action.accept(
location,
getTilesOrNull(location.pos, location.face)
.get(location.layer)
);
});
}
public BlockLogic getBlock(Vec3i blockInChunk) {
return BlockLogicRegistry.getInstance().get(
getData().getBlock(blockInChunk).getId()
);
}
public List<TileLogic> getTiles(Vec3i blockInChunk, BlockFace face) {
return wrapTileList(getData().getTiles(blockInChunk, face));
}
public List<TileLogic> getTilesOrNull(Vec3i blockInChunk, BlockFace face) {
List<TileData> tiles = getData().getTilesOrNull(blockInChunk, face);
if (tiles == null) return null;
return wrapTileList(tiles);
}
private List<TileLogic> wrapTileList(List<TileData> tileDataList) {
return tileLogicLists.computeIfAbsent(
tileDataList,
ChunkLogic::createWrapper
);
}
private static List<TileLogic> createWrapper(List<TileData> tileDataList) {
return Lists.transform(
tileDataList,
data -> TileLogicRegistry.getInstance().get(data.getId())
);
}
}

View File

@ -3,57 +3,15 @@ package ru.windcorp.progressia.server.world;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.block.BlockTickContext;
public class MutableBlockTickContext implements BlockTickContext {
private double tickLength;
private Server server;
private WorldLogic world;
private ChunkLogic chunk;
public class MutableBlockTickContext
extends MutableChunkTickContext
implements BlockTickContext {
private final Vec3i blockInWorld = new Vec3i();
private final Vec3i blockInChunk = new Vec3i();
public double getTickLength() {
return tickLength;
}
public void setTickLength(double tickLength) {
this.tickLength = tickLength;
}
@Override
public Server getServer() {
return server;
}
public void setServer(Server server) {
this.server = server;
setWorld(server.getWorld());
}
@Override
public WorldLogic getWorld() {
return world;
}
public void setWorld(WorldLogic world) {
this.world = world;
}
@Override
public ChunkLogic getChunk() {
return chunk;
}
public void setChunk(ChunkLogic chunk) {
this.chunk = chunk;
}
@Override
public Vec3i getCoords() {
return this.blockInWorld;
@ -82,10 +40,4 @@ public class MutableBlockTickContext implements BlockTickContext {
);
}
@Override
public void requestBlockTick(Vec3i blockInWorld) {
// TODO implement
throw new UnsupportedOperationException("Not yet implemented");
}
}

View File

@ -0,0 +1,66 @@
package ru.windcorp.progressia.server.world;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.block.BlockFace;
import ru.windcorp.progressia.server.Server;
public class MutableChunkTickContext implements ChunkTickContext {
private double tickLength;
private Server server;
private WorldLogic world;
private ChunkLogic chunk;
public MutableChunkTickContext() {
super();
}
public double getTickLength() {
return tickLength;
}
public void setTickLength(double tickLength) {
this.tickLength = tickLength;
}
@Override
public Server getServer() {
return server;
}
public void setServer(Server server) {
this.server = server;
setWorld(server.getWorld());
}
@Override
public WorldLogic getWorld() {
return world;
}
public void setWorld(WorldLogic world) {
this.world = world;
}
@Override
public ChunkLogic getChunk() {
return chunk;
}
public void setChunk(ChunkLogic chunk) {
this.chunk = chunk;
}
@Override
public void requestBlockTick(Vec3i blockInWorld) {
// TODO implement
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void requestTileTick(Vec3i blockInWorld, BlockFace face, int layer) {
// TODO implement
throw new UnsupportedOperationException("Not yet implemented");
}
}

View File

@ -0,0 +1,65 @@
package ru.windcorp.progressia.server.world;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.block.BlockFace;
import ru.windcorp.progressia.server.world.tile.TileTickContext;
public class MutableTileTickContext
extends MutableChunkTickContext
implements TileTickContext {
private final Vec3i blockInWorld = new Vec3i();
private final Vec3i blockInChunk = new Vec3i();
private BlockFace face;
private int layer;
@Override
public Vec3i getCoords() {
return this.blockInWorld;
}
@Override
public Vec3i getChunkCoords() {
return this.blockInChunk;
}
public void setCoordsInWorld(Vec3i coords) {
getCoords().set(coords.x, coords.y, coords.z);
Coordinates.convertInWorldToInChunk(getCoords(), getChunkCoords());
Vec3i chunk = Vectors.grab3i();
Coordinates.convertInWorldToChunk(coords, chunk);
setChunk(getWorld().getChunk(chunk));
Vectors.release(chunk);
}
public void setCoordsInChunk(Vec3i coords) {
getChunkCoords().set(coords.x, coords.y, coords.z);
Coordinates.getInWorld(
getChunkData().getPosition(), getChunkCoords(),
getCoords()
);
}
@Override
public BlockFace getFace() {
return face;
}
public void setFace(BlockFace face) {
this.face = face;
}
@Override
public int getLayer() {
return layer;
}
public void setLayer(int layer) {
this.layer = layer;
}
}

View File

@ -2,6 +2,7 @@ package ru.windcorp.progressia.server.world;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.common.world.block.BlockFace;
import ru.windcorp.progressia.server.Server;
public interface TickContext {
@ -19,5 +20,7 @@ public interface TickContext {
}
void requestBlockTick(Vec3i blockInWorld);
void requestTileTick(Vec3i blockInWorld, BlockFace face, int layer);
}

View File

@ -1,7 +1,8 @@
package ru.windcorp.progressia.server.world;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.block.Tickable;
import ru.windcorp.progressia.server.world.block.TickableBlock;
import ru.windcorp.progressia.server.world.tile.TickableTile;
public class Ticker implements Runnable {
@ -11,6 +12,9 @@ public class Ticker implements Runnable {
private final MutableBlockTickContext blockTickContext =
new MutableBlockTickContext();
private final MutableTileTickContext tileTickContext =
new MutableTileTickContext();
private final Server server;
public Ticker(Server server) {
@ -26,30 +30,41 @@ public class Ticker implements Runnable {
}
private void tickChunk(ChunkLogic chunk) {
MutableBlockTickContext context = this.blockTickContext;
MutableBlockTickContext blockContext = this.blockTickContext;
MutableTileTickContext tileContext = this.tileTickContext;
context.setServer(server);
context.setChunk(chunk);
blockContext.setServer(server);
tileContext.setServer(server);
tickRegularBlocks(chunk, context);
tickRandomBlocks(chunk, context);
tickRegularTickers(chunk, blockContext, tileContext);
tickRandomBlocks(chunk, blockContext, tileContext);
flushChanges(chunk);
}
private void tickRegularBlocks(
private void tickRegularTickers(
ChunkLogic chunk,
MutableBlockTickContext context
MutableBlockTickContext blockContext,
MutableTileTickContext tileContext
) {
chunk.forEachTickingBlock((blockInChunk, block) -> {
context.setCoordsInChunk(blockInChunk);
((Tickable) block).tick(context, tracker);
blockContext.setCoordsInChunk(blockInChunk);
((TickableBlock) block).tick(blockContext, tracker);
});
chunk.forEachTickingTile((locInChunk, tile) -> {
tileContext.setCoordsInChunk(locInChunk.pos);
tileContext.setFace(locInChunk.face);
tileContext.setLayer(locInChunk.layer);
((TickableTile) tile).tick(tileContext, tracker);
});
}
private void tickRandomBlocks(
ChunkLogic chunk,
MutableBlockTickContext context
MutableBlockTickContext blockContext,
MutableTileTickContext tileContext
) {
// TODO implement
}

View File

@ -4,11 +4,12 @@ import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockFace;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.ChunkLogic;
import ru.windcorp.progressia.server.world.WorldLogic;
public class ForwardingBlockTickContext {
public class ForwardingBlockTickContext implements BlockTickContext {
private BlockTickContext parent;
@ -24,46 +25,62 @@ public class ForwardingBlockTickContext {
this.parent = parent;
}
@Override
public ChunkLogic getChunk() {
return parent.getChunk();
}
@Override
public ChunkData getChunkData() {
return parent.getChunkData();
}
@Override
public double getTickLength() {
return parent.getTickLength();
}
@Override
public Server getServer() {
return parent.getServer();
}
@Override
public Vec3i getCoords() {
return parent.getCoords();
}
@Override
public WorldLogic getWorld() {
return parent.getWorld();
}
@Override
public WorldData getWorldData() {
return parent.getWorldData();
}
@Override
public Vec3i getChunkCoords() {
return parent.getChunkCoords();
}
@Override
public void requestBlockTick(Vec3i blockInWorld) {
parent.requestBlockTick(blockInWorld);
}
@Override
public void requestTileTick(Vec3i blockInWorld, BlockFace face, int layer) {
parent.requestTileTick(blockInWorld, face, layer);
}
@Override
public BlockLogic getBlock() {
return parent.getBlock();
}
@Override
public BlockData getBlockData() {
return parent.getBlockData();
}

View File

@ -2,7 +2,7 @@ package ru.windcorp.progressia.server.world.block;
import ru.windcorp.progressia.server.world.Changer;
public interface Tickable {
public interface TickableBlock {
void tick(BlockTickContext context, Changer changer);

View File

@ -2,7 +2,7 @@ package ru.windcorp.progressia.server.world.block;
import ru.windcorp.progressia.server.world.Changer;
public interface Updatable {
public interface UpdatableBlock {
void update(BlockTickContext context, Changer changer);

View File

@ -0,0 +1,132 @@
package ru.windcorp.progressia.server.world.tile;
import java.util.List;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockFace;
import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.ChunkLogic;
import ru.windcorp.progressia.server.world.WorldLogic;
import ru.windcorp.progressia.server.world.block.BlockLogic;
public class ForwardingTileTickContext implements TileTickContext {
private TileTickContext parent;
public ForwardingTileTickContext(TileTickContext parent) {
this.parent = parent;
}
public TileTickContext getParent() {
return parent;
}
public void setParent(TileTickContext parent) {
this.parent = parent;
}
@Override
public ChunkLogic getChunk() {
return parent.getChunk();
}
@Override
public ChunkData getChunkData() {
return parent.getChunkData();
}
@Override
public double getTickLength() {
return parent.getTickLength();
}
@Override
public Server getServer() {
return parent.getServer();
}
@Override
public WorldLogic getWorld() {
return parent.getWorld();
}
@Override
public WorldData getWorldData() {
return parent.getWorldData();
}
@Override
public void requestBlockTick(Vec3i blockInWorld) {
parent.requestBlockTick(blockInWorld);
}
@Override
public void requestTileTick(Vec3i blockInWorld, BlockFace face, int layer) {
parent.requestTileTick(blockInWorld, face, layer);
}
@Override
public Vec3i getCoords() {
return parent.getCoords();
}
@Override
public Vec3i getChunkCoords() {
return parent.getChunkCoords();
}
@Override
public BlockFace getFace() {
return parent.getFace();
}
@Override
public int getLayer() {
return parent.getLayer();
}
@Override
public TileLogic getTile() {
return parent.getTile();
}
@Override
public TileData getTileData() {
return parent.getTileData();
}
@Override
public List<TileLogic> getTiles() {
return parent.getTiles();
}
@Override
public List<TileLogic> getTilesOrNull() {
return parent.getTilesOrNull();
}
@Override
public List<TileData> getTileDataList() {
return parent.getTileDataList();
}
@Override
public List<TileData> getTileDataListOrNull() {
return parent.getTileDataListOrNull();
}
@Override
public BlockLogic getBlock() {
return parent.getBlock();
}
@Override
public BlockData getBlockData() {
return parent.getBlockData();
}
}

View File

@ -0,0 +1,17 @@
package ru.windcorp.progressia.server.world.tile;
import ru.windcorp.progressia.server.world.Changer;
public interface TickableTile {
void tick(TileTickContext context, Changer changer);
default boolean doesTickRegularly(TileTickContext context) {
return false;
}
default boolean doesTickRandomly(TileTickContext context) {
return false;
}
}

View File

@ -0,0 +1,28 @@
package ru.windcorp.progressia.server.world.tile;
import ru.windcorp.progressia.common.util.Namespaced;
import ru.windcorp.progressia.common.world.block.BlockFace;
public class TileLogic extends Namespaced {
public TileLogic(String namespace, String name) {
super(namespace, name);
}
public boolean canOccupyFace(TileTickContext context) {
return canOccupyFace(context.getFace());
}
public boolean canOccupyFace(BlockFace face) {
return true;
}
public boolean isSolid(TileTickContext context) {
return isSolid();
}
public boolean isSolid() {
return false;
}
}

View File

@ -0,0 +1,13 @@
package ru.windcorp.progressia.server.world.tile;
import ru.windcorp.progressia.common.util.NamespacedRegistry;
public class TileLogicRegistry extends NamespacedRegistry<TileLogic> {
private static final TileLogicRegistry INSTANCE = new TileLogicRegistry();
public static TileLogicRegistry getInstance() {
return INSTANCE;
}
}

View File

@ -0,0 +1,71 @@
package ru.windcorp.progressia.server.world.tile;
import java.util.List;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockFace;
import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.server.world.ChunkTickContext;
import ru.windcorp.progressia.server.world.block.BlockLogic;
public interface TileTickContext extends ChunkTickContext {
/**
* Returns the current world coordinates.
* @return the world coordinates of the tile being ticked
*/
Vec3i getCoords();
/**
* Returns the current chunk coordinates.
* @return the chunk coordinates of the tile being ticked
*/
Vec3i getChunkCoords();
/**
* Returns the current block face. This face is always
* {@linkplain BlockFace#isPrimary() primary}.
* @return the block face that the tile being ticked occupies
*/
BlockFace getFace();
/**
* Returns the current layer.
* @return the layer that the tile being ticked occupies in the tile stack
*/
int getLayer();
default TileLogic getTile() {
return getTiles().get(getLayer());
}
default TileData getTileData() {
return getTileDataList().get(getLayer());
}
default List<TileLogic> getTiles() {
return getChunk().getTiles(getChunkCoords(), getFace());
}
default List<TileLogic> getTilesOrNull() {
return getChunk().getTilesOrNull(getChunkCoords(), getFace());
}
default List<TileData> getTileDataList() {
return getChunkData().getTiles(getChunkCoords(), getFace());
}
default List<TileData> getTileDataListOrNull() {
return getChunkData().getTilesOrNull(getChunkCoords(), getFace());
}
default BlockLogic getBlock() {
return getChunk().getBlock(getChunkCoords());
}
default BlockData getBlockData() {
return getChunkData().getBlock(getChunkCoords());
}
}

View File

@ -0,0 +1,9 @@
package ru.windcorp.progressia.server.world.tile;
import ru.windcorp.progressia.server.world.Changer;
public interface UpdatableTile {
void update(TileTickContext context, Changer changer);
}