From 60fbfa9578d10714c9a10bc90756dd3a7a66d843 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Thu, 27 Aug 2020 00:24:11 +0300 Subject: [PATCH] Added tiles. Not yet optimized. --- .../progressia/client/ClientProxy.java | 2 + .../graphics/model/BlockFaceVectors.java | 12 +- .../progressia/client/world/ChunkRender.java | 121 ++++++++++--- .../client/world/renders/TileRender.java | 33 ++++ .../world/renders/TileRenderSimple.java | 47 +++++ .../client/world/renders/TileRenders.java | 60 +++++++ .../progressia/common/block/BlockFace.java | 45 ++++- .../progressia/common/block/TileData.java | 28 +++ .../common/block/TileDataRegistry.java | 39 +++++ .../common/util/SizeLimitedList.java | 71 ++++++++ .../progressia/common/world/ChunkData.java | 164 +++++++++++++++--- .../progressia/common/world/WorldData.java | 2 +- .../assets/textures/tiles/stones.png | Bin 0 -> 464 bytes 13 files changed, 568 insertions(+), 56 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/client/world/renders/TileRender.java create mode 100644 src/main/java/ru/windcorp/progressia/client/world/renders/TileRenderSimple.java create mode 100644 src/main/java/ru/windcorp/progressia/client/world/renders/TileRenders.java create mode 100644 src/main/java/ru/windcorp/progressia/common/block/TileData.java create mode 100644 src/main/java/ru/windcorp/progressia/common/block/TileDataRegistry.java create mode 100644 src/main/java/ru/windcorp/progressia/common/util/SizeLimitedList.java create mode 100644 src/main/resources/assets/textures/tiles/stones.png diff --git a/src/main/java/ru/windcorp/progressia/client/ClientProxy.java b/src/main/java/ru/windcorp/progressia/client/ClientProxy.java index 9ccb063..9115390 100644 --- a/src/main/java/ru/windcorp/progressia/client/ClientProxy.java +++ b/src/main/java/ru/windcorp/progressia/client/ClientProxy.java @@ -30,6 +30,7 @@ import ru.windcorp.progressia.client.graphics.texture.Atlases; import ru.windcorp.progressia.client.graphics.world.LayerWorld; import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; import ru.windcorp.progressia.client.world.renders.BlockRenders; +import ru.windcorp.progressia.client.world.renders.TileRenders; import ru.windcorp.progressia.common.resource.ResourceManager; public class ClientProxy implements Proxy { @@ -47,6 +48,7 @@ public class ClientProxy implements Proxy { } BlockRenders.registerTest(); + TileRenders.registerTest(); Atlases.loadAllAtlases(); GUI.addBottomLayer(new LayerWorld()); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java index 6fa6651..0426dcd 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java @@ -11,13 +11,13 @@ class BlockFaceVectors { private static BlockFaceVectors createInner(BlockFaceVectors outer) { ImmutableMap.Builder originBuilder = - ImmutableMap.builderWithExpectedSize(count()); + ImmutableMap.builder(); ImmutableMap.Builder widthBuilder = - ImmutableMap.builderWithExpectedSize(count()); + ImmutableMap.builder(); ImmutableMap.Builder heightBuilder = - ImmutableMap.builderWithExpectedSize(count()); + ImmutableMap.builder(); for (BlockFace face : getFaces()) { Vec3 width = outer.getWidth(face); @@ -43,7 +43,7 @@ class BlockFaceVectors { static { OUTER = new BlockFaceVectors( - ImmutableMap.builderWithExpectedSize(count()) + ImmutableMap.builder() .put(TOP, new Vec3(-0.5f, +0.5f, +0.5f)) .put(BOTTOM, new Vec3(-0.5f, -0.5f, -0.5f)) @@ -54,7 +54,7 @@ class BlockFaceVectors { .build(), - ImmutableMap.builderWithExpectedSize(count()) + ImmutableMap.builder() .put(TOP, new Vec3( 0, -1, 0)) .put(BOTTOM, new Vec3( 0, +1, 0)) @@ -65,7 +65,7 @@ class BlockFaceVectors { .build(), - ImmutableMap.builderWithExpectedSize(count()) + ImmutableMap.builder() .put(TOP, new Vec3(+1, 0, 0)) .put(BOTTOM, new Vec3(+1, 0, 0)) diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java index 1495f8e..dea8fa2 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java @@ -18,9 +18,11 @@ package ru.windcorp.progressia.client.world; import java.util.Collection; +import java.util.List; import java.util.stream.Collectors; import glm.mat._4.Mat4; +import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.Model; import ru.windcorp.progressia.client.graphics.model.Shape; @@ -31,9 +33,14 @@ import ru.windcorp.progressia.client.graphics.model.StaticModel.Builder; import ru.windcorp.progressia.client.world.renders.BlockRender; import ru.windcorp.progressia.client.world.renders.BlockRenderNone; import ru.windcorp.progressia.client.world.renders.BlockRenders; +import ru.windcorp.progressia.client.world.renders.TileRender; +import ru.windcorp.progressia.client.world.renders.TileRenders; import ru.windcorp.progressia.client.world.renders.cro.ChunkRenderOptimizer; import ru.windcorp.progressia.client.world.renders.cro.ChunkRenderOptimizerSupplier; import ru.windcorp.progressia.client.world.renders.cro.ChunkRenderOptimizers; +import ru.windcorp.progressia.common.block.BlockFace; +import ru.windcorp.progressia.common.block.TileData; +import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; public class ChunkRender { @@ -101,23 +108,8 @@ public class ChunkRender { for (int z = 0; z < ChunkData.BLOCKS_PER_CHUNK; ++z) { cursor.set(x, y, z); - BlockRender block = getBlock(cursor); - - if (block instanceof BlockRenderNone) { - continue; - } - - forwardToOptimizers(block, x, y, z, optimizers); - - if (!block.needsOwnRenderable()) { - continue; - } - - if (tryToCreateRenderable(block, x, y, z, builder)) { - continue; - } - - addRenderAsRenderable(block, x, y, z, builder); + buildBlock(cursor, optimizers, builder); + buildBlockTiles(cursor, optimizers, builder); } } } @@ -133,14 +125,41 @@ public class ChunkRender { needsUpdate = false; } - private void forwardToOptimizers( + private void buildBlock( + Vec3i cursor, + Collection optimizers, + Builder builder + ) { + BlockRender block = getBlock(cursor); + int x = cursor.x; + int y = cursor.y; + int z = cursor.z; + + if (block instanceof BlockRenderNone) { + return; + } + + forwardBlockToOptimizers(block, x, y, z, optimizers); + + if (!block.needsOwnRenderable()) { + return; + } + + if (tryToCreateBlockRenderable(block, x, y, z, builder)) { + return; + } + + addBlockRenderAsRenderable(block, x, y, z, builder); + } + + private void forwardBlockToOptimizers( BlockRender block, int x, int y, int z, Collection optimizers ) { optimizers.forEach(bro -> bro.processBlock(block, x, y, z)); } - private boolean tryToCreateRenderable( + private boolean tryToCreateBlockRenderable( BlockRender block, int x, int y, int z, Builder builder ) { @@ -154,7 +173,7 @@ public class ChunkRender { return true; } - private void addRenderAsRenderable( + private void addBlockRenderAsRenderable( BlockRender block, int x, int y, int z, Builder builder ) { @@ -164,4 +183,66 @@ public class ChunkRender { ); } + private void buildBlockTiles( + Vec3i cursor, + Collection optimizers, + Builder builder + ) { + for (BlockFace face : BlockFace.getFaces()) { + buildFaceTiles(cursor, face, optimizers, builder); + } + } + + private void buildFaceTiles( + Vec3i cursor, BlockFace face, + Collection optimizers, + Builder builder + ) { + List tiles = getData().getTilesOrNull(cursor, face); + + if (tiles == null) { + return; + } + + for (int layer = 0; layer < tiles.size(); ++layer) { + + if (tiles.get(layer) == null) { + System.out.println(tiles.get(layer).getId()); + } + + buildTile( + cursor, face, + TileRenders.get(tiles.get(layer).getId()), + layer, + optimizers, builder + ); + } + } + + private void buildTile( + Vec3i cursor, BlockFace face, + TileRender tile, + int layer, + Collection optimizers, + Builder builder + ) { + // TODO implement + + Vec3 pos = Vectors.grab3().set(cursor.x, cursor.y, cursor.z); + + Vec3 offset = Vectors.grab3().set( + face.getVector().x, face.getVector().y, face.getVector().z + ); + + pos.add(offset.mul(1f / 64)); + + builder.addPart( + tile.createRenderable(face), + new Mat4().identity().translate(pos) + ); + + Vectors.release(pos); + Vectors.release(offset); + } + } diff --git a/src/main/java/ru/windcorp/progressia/client/world/renders/TileRender.java b/src/main/java/ru/windcorp/progressia/client/world/renders/TileRender.java new file mode 100644 index 0000000..d7c5b5f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/world/renders/TileRender.java @@ -0,0 +1,33 @@ +package ru.windcorp.progressia.client.world.renders; + +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.client.graphics.model.WorldRenderable; +import ru.windcorp.progressia.client.world.renders.cro.ChunkRenderOptimizer; +import ru.windcorp.progressia.common.block.BlockFace; +import ru.windcorp.progressia.common.util.Namespaced; + +public class TileRender extends Namespaced { + + public TileRender(String namespace, String name) { + super(namespace, name); + } + + public void render(ShapeRenderHelper renderer, BlockFace face) { + throw new UnsupportedOperationException( + "TileRender.render() not implemented in " + this + ); + } + + public WorldRenderable createRenderable(BlockFace face) { + return null; + } + + public boolean canBeOptimized(ChunkRenderOptimizer optimizer) { + return true; + } + + public boolean needsOwnRenderable() { + return true; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/renders/TileRenderSimple.java b/src/main/java/ru/windcorp/progressia/client/world/renders/TileRenderSimple.java new file mode 100644 index 0000000..61dbf52 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/world/renders/TileRenderSimple.java @@ -0,0 +1,47 @@ +package ru.windcorp.progressia.client.world.renders; + +import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.graphics.backend.Usage; +import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.Shape; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; +import ru.windcorp.progressia.client.graphics.model.WorldRenderable; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; +import ru.windcorp.progressia.common.block.BlockFace; +import ru.windcorp.progressia.common.util.Vectors; + +public class TileRenderSimple extends TileRender { + + private final Texture texture; + + public TileRenderSimple(String namespace, String name, Texture texture) { + super(namespace, name); + this.texture = texture; + } + + public Texture getTexture() { + return texture; + } + + @Override + public WorldRenderable createRenderable(BlockFace face) { + ShapeRenderProgram program = WorldRenderProgram.getDefault(); + + Vec3 color = Vectors.grab3().set(1, 1, 1); + Vec3 center = Vectors.grab3().set(0, 0, 0); + + try { + return new Shape( + Usage.STATIC, WorldRenderProgram.getDefault(), + Faces.createBlockFace( + program, texture, color, center, face, false + ) + ); + } finally { + Vectors.release(color); + Vectors.release(center); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/renders/TileRenders.java b/src/main/java/ru/windcorp/progressia/client/world/renders/TileRenders.java new file mode 100644 index 0000000..3c464ee --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/world/renders/TileRenders.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Progressia + * Copyright (C) 2020 Wind Corporation + * + * 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 . + *******************************************************************************/ +package ru.windcorp.progressia.client.world.renders; + +import java.util.HashMap; +import java.util.Map; + +import ru.windcorp.progressia.client.graphics.texture.Atlases; +import ru.windcorp.progressia.client.graphics.texture.Atlases.AtlasGroup; +import ru.windcorp.progressia.client.graphics.texture.SimpleTexture; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.common.resource.ResourceManager; + +public class TileRenders { + + private static final Map TILE_RENDERS = + new HashMap<>(); + + private static final AtlasGroup TILES_ATLAS_GROUP = + new AtlasGroup("Tiles", 1 << 12); + + private TileRenders() {} + + public static void registerTest() { + register(new TileRenderSimple("Test", "Stones", getTexture("stones"))); + } + + public static TileRender get(String name) { + return TILE_RENDERS.get(name); + } + + public static void register(TileRender tileRender) { + TILE_RENDERS.put(tileRender.getId(), tileRender); + } + + public static Texture getTexture(String name) { + return new SimpleTexture( + Atlases.getSprite( + ResourceManager.getTextureResource("tiles/" + name), + TILES_ATLAS_GROUP + ) + ); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/block/BlockFace.java b/src/main/java/ru/windcorp/progressia/common/block/BlockFace.java index 7382bde..2553f46 100644 --- a/src/main/java/ru/windcorp/progressia/common/block/BlockFace.java +++ b/src/main/java/ru/windcorp/progressia/common/block/BlockFace.java @@ -19,6 +19,8 @@ package ru.windcorp.progressia.common.block; import com.google.common.collect.ImmutableList; +import glm.vec._3.i.Vec3i; + public final class BlockFace extends BlockRelation { public static final BlockFace @@ -35,6 +37,8 @@ public final class BlockFace extends BlockRelation { private static final ImmutableList PRIMARY_FACES = ImmutableList.of(TOP, NORTH, WEST); + public static final int BLOCK_FACE_COUNT = ALL_FACES.size(); + public static ImmutableList getFaces() { return ALL_FACES; } @@ -43,10 +47,6 @@ public final class BlockFace extends BlockRelation { return PRIMARY_FACES; } - public static int count() { - return ALL_FACES.size(); - } - static { link(TOP, BOTTOM); link(NORTH, SOUTH); @@ -58,11 +58,15 @@ public final class BlockFace extends BlockRelation { b.counterFace = a; } + private static int nextId = 0; + + private final int id; private BlockFace counterFace; private final boolean isPrimary; private BlockFace(int x, int y, int z, boolean isPrimary) { super(x, y, z); + this.id = nextId++; this.isPrimary = isPrimary; } @@ -75,9 +79,42 @@ public final class BlockFace extends BlockRelation { else return counterFace; } + public BlockFace getPrimaryAndMoveCursor(Vec3i cursor) { + if (isPrimary) return this; + + cursor.add(getVector()); + return counterFace; + } + public BlockFace getSecondary() { if (isPrimary) return counterFace; else return this; } + + public BlockFace getSecondaryAndMoveCursor(Vec3i cursor) { + if (!isPrimary) return this; + + cursor.add(getVector()); + return counterFace; + } + + public int getId() { + return id; + } + + @Override + public float getEuclideanDistance() { + return 1.0f; + } + + @Override + public int getChebyshevDistance() { + return 1; + } + + @Override + public int getManhattanDistance() { + return 1; + } } diff --git a/src/main/java/ru/windcorp/progressia/common/block/TileData.java b/src/main/java/ru/windcorp/progressia/common/block/TileData.java new file mode 100644 index 0000000..8a68cca --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/block/TileData.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Progressia + * Copyright (C) 2020 Wind Corporation + * + * 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 . + *******************************************************************************/ +package ru.windcorp.progressia.common.block; + +import ru.windcorp.progressia.common.util.Namespaced; + +public class TileData extends Namespaced { + + public TileData(String namespace, String name) { + super(namespace, name); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/block/TileDataRegistry.java b/src/main/java/ru/windcorp/progressia/common/block/TileDataRegistry.java new file mode 100644 index 0000000..9e9650f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/block/TileDataRegistry.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Progressia + * Copyright (C) 2020 Wind Corporation + * + * 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 . + *******************************************************************************/ +package ru.windcorp.progressia.common.block; + +import java.util.HashMap; +import java.util.Map; + +public class TileDataRegistry { + + private static final Map REGISTRY = new HashMap<>(); + + static { + register(new TileData("Test", "Stones")); + } + + public static TileData get(String name) { + return REGISTRY.get(name); + } + + public static void register(TileData tileData) { + REGISTRY.put(tileData.getId(), tileData); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/SizeLimitedList.java b/src/main/java/ru/windcorp/progressia/common/util/SizeLimitedList.java new file mode 100644 index 0000000..09c3f26 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/SizeLimitedList.java @@ -0,0 +1,71 @@ +package ru.windcorp.progressia.common.util; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.RandomAccess; + +import com.google.common.collect.ForwardingList; + +public class SizeLimitedList extends ForwardingList { + + private static final class RandomAccessSizeLimitedList + extends SizeLimitedList + implements RandomAccess { + protected RandomAccessSizeLimitedList(List parent, int maxSize) { + super(parent, maxSize); + } + } + + public static List wrap(List list, int maxSize) { + if (list instanceof RandomAccess) { + return new RandomAccessSizeLimitedList<>(list, maxSize); + } else { + return new SizeLimitedList<>(list, maxSize); + } + } + + private final List delegate; + + private final int maxSize; + + protected SizeLimitedList(List parent, int maxSize) { + this.delegate = Objects.requireNonNull(parent, "parent"); + this.maxSize = maxSize; + } + + @Override + public boolean addAll(Collection collection) { + return standardAddAll(collection); + } + + @Override + public boolean addAll(int index, Collection elements) { + return standardAddAll(index, elements); + } + + public boolean add(E e) { + checkMaxSize(); + return delegate().add(e); + } + + @Override + public void add(int index, final E e) { + checkMaxSize(); + delegate().add(index, e); + } + + private void checkMaxSize() { + if (size() >= maxSize) { + throw new UnsupportedOperationException( + "Maximum size " + maxSize + " reached" + ); + } + } + + @Override + protected List delegate() { + return delegate; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index 33e9e8e..58671df 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -17,9 +17,21 @@ *******************************************************************************/ package ru.windcorp.progressia.common.world; +import static ru.windcorp.progressia.common.block.BlockFace.*; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.collect.Lists; + import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.block.BlockData; import ru.windcorp.progressia.common.block.BlockDataRegistry; +import ru.windcorp.progressia.common.block.BlockFace; +import ru.windcorp.progressia.common.block.TileData; +import ru.windcorp.progressia.common.block.TileDataRegistry; +import ru.windcorp.progressia.common.util.SizeLimitedList; +import ru.windcorp.progressia.common.util.Vectors; public class ChunkData { @@ -27,23 +39,33 @@ public class ChunkData { public static final int TILES_PER_FACE = 8; private final Vec3i position = new Vec3i(); + private final WorldData world; private final BlockData[] blocks = new BlockData[ BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK ]; - private final BlockData grass = BlockDataRegistry.get("Test:Grass"); - private final BlockData dirt = BlockDataRegistry.get("Test:Dirt"); - private final BlockData stone = BlockDataRegistry.get("Test:Stone"); - private final BlockData air = BlockDataRegistry.get("Test:Air"); + @SuppressWarnings("unchecked") + private final List[] tiles = (List[]) new List[ + BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * + BLOCK_FACE_COUNT + ]; - public ChunkData(int x, int y, int z) { + public ChunkData(int x, int y, int z, WorldData world) { this.position.set(x, y, z); + this.world = world; tmp_generate(); } private void tmp_generate() { + BlockData grass = BlockDataRegistry.get("Test:Grass"); + BlockData dirt = BlockDataRegistry.get("Test:Dirt"); + BlockData stone = BlockDataRegistry.get("Test:Stone"); + BlockData air = BlockDataRegistry.get("Test:Air"); + + TileData stones = TileDataRegistry.get("Test:Stones"); + Vec3i aPoint = new Vec3i(5, 0, BLOCKS_PER_CHUNK + BLOCKS_PER_CHUNK/2); Vec3i pos = new Vec3i(); @@ -74,46 +96,134 @@ public class ChunkData { for (pos.z = BLOCKS_PER_CHUNK - 1; pos.z >= 0 && getBlock(pos) == air; --pos.z); setBlock(pos, grass); + + int hash = x*x * 13 ^ y*y * 37 ^ pos.z*pos.z * 129; + if (hash % 5 == 0) { + getTiles(pos, BlockFace.TOP).add(stones); + } } } } public BlockData getBlock(Vec3i posInChunk) { - if (!isInBounds(posInChunk)) { - throw new IllegalArgumentException( - "Coordinates " + str(posInChunk) + " " - + "are not legal chunk coordinates" - ); - } - return blocks[getBlockIndex(posInChunk)]; } public void setBlock(Vec3i posInChunk, BlockData block) { - if (!isInBounds(posInChunk)) { - throw new IllegalArgumentException( - "Coordinates " + str(posInChunk) + " " - + "are not legal chunk coordinates" - ); - } - blocks[getBlockIndex(posInChunk)] = block; } - private boolean isInBounds(Vec3i posInChunk) { - return - posInChunk.x >= 0 && posInChunk.x < BLOCKS_PER_CHUNK && - posInChunk.y >= 0 && posInChunk.y < BLOCKS_PER_CHUNK && - posInChunk.z >= 0 && posInChunk.z < BLOCKS_PER_CHUNK; + public List getTilesOrNull(Vec3i blockInChunk, BlockFace face) { + return tiles[getTileIndex(blockInChunk, face)]; } - private int getBlockIndex(Vec3i posInChunk) { + /** + * Internal use only. Modify a list returned by + * {@link #getTiles(Vec3i, BlockFace)} or + * {@link #getTilesOrNull(Vec3i, BlockFace)} + * to change tiles. + */ + protected void setTiles( + Vec3i blockInChunk, BlockFace face, + List tiles + ) { + this.tiles[getTileIndex(blockInChunk, face)] = tiles; + } + + public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { + return getTilesOrNull(blockInChunk, face) != null; + } + + public List getTiles(Vec3i blockInChunk, BlockFace face) { + int index = getTileIndex(blockInChunk, face); + + if (tiles[index] == null) { + createTileContainer(blockInChunk, face); + } + + return tiles[index]; + } + + private void createTileContainer(Vec3i blockInChunk, BlockFace face) { + if (isBorder(blockInChunk, face)) { + createBorderTileContainer(blockInChunk, face); + } else { + createNormalTileContainer(blockInChunk, face); + } + } + + private void createNormalTileContainer(Vec3i blockInChunk, BlockFace face) { + List primaryList = + SizeLimitedList.wrap( + new ArrayList<>(TILES_PER_FACE), TILES_PER_FACE + ); + + List secondaryList = Lists.reverse(primaryList); + + + Vec3i cursor = Vectors.grab3i() + .set(blockInChunk.x, blockInChunk.y, blockInChunk.z); + + face = face.getPrimaryAndMoveCursor(cursor); + setTiles(cursor, face, primaryList); + + face = face.getSecondaryAndMoveCursor(cursor); + setTiles(cursor, face, secondaryList); + } + + private void createBorderTileContainer(Vec3i blockInChunk, BlockFace face) { + // TODO cooperate with neighbours + setTiles( + blockInChunk, face, + SizeLimitedList.wrap( + new ArrayList<>(TILES_PER_FACE), TILES_PER_FACE + ) + ); + } + + private static int getBlockIndex(Vec3i posInChunk) { + checkLocalCoordinates(posInChunk); + return posInChunk.z * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK + posInChunk.y * BLOCKS_PER_CHUNK + posInChunk.x; } + private static int getTileIndex(Vec3i posInChunk, BlockFace face) { + return + getBlockIndex(posInChunk) * BLOCK_FACE_COUNT + + face.getId(); + } + + private static void checkLocalCoordinates(Vec3i posInChunk) { + if (!isInBounds(posInChunk)) { + throw new IllegalArgumentException( + "Coordinates " + str(posInChunk) + " " + + "are not legal chunk coordinates" + ); + } + } + + private static boolean isInBounds(Vec3i posInChunk) { + return + posInChunk.x >= 0 && posInChunk.x < BLOCKS_PER_CHUNK && + posInChunk.y >= 0 && posInChunk.y < BLOCKS_PER_CHUNK && + posInChunk.z >= 0 && posInChunk.z < BLOCKS_PER_CHUNK; + } + + private boolean isBorder(Vec3i blockInChunk, BlockFace face) { + final int min = 0, max = BLOCKS_PER_CHUNK - 1; + + return + (blockInChunk.x == min && face == SOUTH ) || + (blockInChunk.x == max && face == NORTH ) || + (blockInChunk.y == min && face == WEST ) || + (blockInChunk.y == max && face == EAST ) || + (blockInChunk.z == min && face == BOTTOM) || + (blockInChunk.z == max && face == TOP ); + } + public int getX() { return position.x; } @@ -130,6 +240,10 @@ public class ChunkData { return position; } + public WorldData getWorld() { + return world; + } + private static String str(Vec3i v) { return "(" + v.x + "; " + v.y + "; " + v.z + ")"; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java index cff9cc4..93113fc 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java @@ -34,7 +34,7 @@ public class WorldData { for (int x = -(size / 2); x <= (size / 2); ++x) { for (int y = -(size / 2); y <= (size / 2); ++y) { - chunks.put(CoordinatePacker.pack3IntsIntoLong(x, y, 0), new ChunkData(x, y, 0)); + chunks.put(CoordinatePacker.pack3IntsIntoLong(x, y, 0), new ChunkData(x, y, 0, this)); } } } diff --git a/src/main/resources/assets/textures/tiles/stones.png b/src/main/resources/assets/textures/tiles/stones.png new file mode 100644 index 0000000000000000000000000000000000000000..a883e770ab16ecdef5cd0fbe95d4870343f7368f GIT binary patch literal 464 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkEbHUgGKN%Kn5yO4v$POlmba% zUEkQ>7J1yN>%s5yFTUrm+`>4q%}+AEkZ12@kIT7<&fk}vKAZMAL6h;oCY?CF=>}RX z*LrfdIZsP%ZFu=tWLxfK{$>N7gJ%R*By7IxVE#j|L+Mc-jZfdzN-E}zt#qqS7zx4vBj^Cbg=*|rH5TULCK z718qIZ00dp_uAvKiTPZ6#