diff options
author | olamedia <[email protected]> | 2012-10-17 09:52:48 +0600 |
---|---|---|
committer | olamedia <[email protected]> | 2012-10-17 09:52:48 +0600 |
commit | 5320fd1dad5b77fa227e83fbbe0a958f2c5fc283 (patch) | |
tree | 1b49b91cf820ad5536241fa093c34fd2ae9731db /src/ru/olamedia/olacraft/world | |
parent | e2b667011c8fc93388c3ebee6e2a64090456e2a1 (diff) |
fps
Diffstat (limited to 'src/ru/olamedia/olacraft/world')
16 files changed, 627 insertions, 66 deletions
diff --git a/src/ru/olamedia/olacraft/world/block/Block.java b/src/ru/olamedia/olacraft/world/block/Block.java index 44e9b1d..50752f0 100644 --- a/src/ru/olamedia/olacraft/world/block/Block.java +++ b/src/ru/olamedia/olacraft/world/block/Block.java @@ -1,34 +1,73 @@ package ru.olamedia.olacraft.world.block; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLContext; import javax.vecmath.Vector3f; import ru.olamedia.camera.MatrixCamera; +import ru.olamedia.olacraft.game.Game; import ru.olamedia.olacraft.world.blockTypes.BlockType; import ru.olamedia.olacraft.world.blockTypes.EmptyBlockType; +import ru.olamedia.olacraft.world.chunk.Chunk; import ru.olamedia.olacraft.world.chunk.ChunkUnavailableException; +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.location.BlockLocation; import ru.olamedia.olacraft.world.provider.WorldProvider; public class Block { - private WorldProvider provider; - private int x; - private int y; - private int z; + public WorldProvider provider; + public BlockLocation location = new BlockLocation(); + + public void removeFromWorld() { + ChunkData cdata = provider.getChunk(location.getChunkLocation()); + cdata.setEmpty(location, true); + Chunk chunk = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation()); + chunk.invalidate(); + if (location.isChunkEdge()) { + if (location.isChunkBackEdge()) { + Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() + .getBack()); + neighbor.invalidate(); + } else if (location.isChunkFrontEdge()) { + Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() + .getFront()); + neighbor.invalidate(); + } else if (location.isChunkLeftEdge()) { + Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() + .getLeft()); + neighbor.invalidate(); + } else if (location.isChunkRightEdge()) { + Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() + .getRight()); + neighbor.invalidate(); + } else if (location.isChunkTopEdge()) { + Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() + .getTop()); + neighbor.invalidate(); + } else if (location.isChunkBottomEdge()) { + Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() + .getBottom()); + neighbor.invalidate(); + } + } + } /** * Inventory block */ public Block() { this.provider = null; - this.x = 0; - this.y = 0; - this.z = 0; + location.x = 0; + location.y = 0; + location.z = 0; } public void putIntoWorld(WorldProvider worldProvider, int x, int y, int z) { this.provider = worldProvider; - this.x = x; - this.y = y; - this.z = z; + location.x = x; + location.y = y; + location.z = z; } public Block(WorldProvider worldProvider, int x, int y, int z) { @@ -39,7 +78,7 @@ public class Block { * @return the x */ public int getX() { - return x; + return location.x; } /** @@ -47,14 +86,14 @@ public class Block { * the x to set */ public void setX(int x) { - this.x = x; + location.x = x; } /** * @return the y */ public int getY() { - return y; + return location.y; } /** @@ -62,14 +101,14 @@ public class Block { * the y to set */ public void setY(int y) { - this.y = y; + location.y = y; } /** * @return the z */ public int getZ() { - return z; + return location.z; } /** @@ -77,15 +116,15 @@ public class Block { * the z to set */ public void setZ(int z) { - this.z = z; + location.z = z; } public boolean isEmpty() throws ChunkUnavailableException { - return provider.isEmptyBlock(x, y, z); + return provider.isEmptyBlock(location.x, location.y, location.z); } public Block getNeighbor(int dx, int dy, int dz) { - return new Block(provider, x + dx, y + dy, z + dz); + return new Block(provider, location.x + dx, location.y + dy, location.z + dz); } public Block[] getNeighbors() { @@ -153,34 +192,178 @@ public class Block { } private Vector3f getBottomRightBack() { - return new Vector3f(x + 0.5f, y - 0.5f, z - 0.5f); + return new Vector3f(location.x + 0.5f, location.y - 0.5f, location.z - 0.5f); } private Vector3f getBottomRightFront() { - return new Vector3f(x + 0.5f, y - 0.5f, z + 0.5f); + return new Vector3f(location.x + 0.5f, location.y - 0.5f, location.z + 0.5f); } private Vector3f getBottomLeftFront() { - return new Vector3f(x - 0.5f, y - 0.5f, z + 0.5f); + return new Vector3f(location.x - 0.5f, location.y - 0.5f, location.z + 0.5f); } private Vector3f getBottomLeftBack() { - return new Vector3f(x - 0.5f, y - 0.5f, z - 0.5f); + return new Vector3f(location.x - 0.5f, location.y - 0.5f, location.z - 0.5f); } private Vector3f getTopRightBack() { - return new Vector3f(x + 0.5f, y + 0.5f, z - 0.5f); + return new Vector3f(location.x + 0.5f, location.y + 0.5f, location.z - 0.5f); } private Vector3f getTopLeftFront() { - return new Vector3f(x - 0.5f, y + 0.5f, z + 0.5f); + return new Vector3f(location.x - 0.5f, location.y + 0.5f, location.z + 0.5f); } private Vector3f getTopRightFront() { - return new Vector3f(x + 0.5f, y + 0.5f, z + 0.5f); + return new Vector3f(location.x + 0.5f, location.y + 0.5f, location.z + 0.5f); } private Vector3f getTopLeftBack() { - return new Vector3f(x - 0.5f, y + 0.5f, z - 0.5f); + return new Vector3f(location.x - 0.5f, location.y + 0.5f, location.z - 0.5f); + } + + public void request() { + provider.loadChunk(location.getChunkLocation()); + } + + public void renderFrame() { + GL2 gl = GLContext.getCurrentGL().getGL2(); + gl.glDisable(GL2.GL_TEXTURE_2D); + gl.glEnable(GL2.GL_DEPTH_TEST); + gl.glEnable(GL2.GL_LINE_SMOOTH); + gl.glEnable(GL2.GL_POLYGON_SMOOTH); + gl.glHint(GL2.GL_LINE_SMOOTH_HINT, GL2.GL_NICEST); + gl.glHint(GL2.GL_POLYGON_SMOOTH_HINT, GL2.GL_NICEST); + // gl.glEnable(GL2.GL_BLEND); // Enable Blending + // gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE); + gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_FILL); + float min = 0.505f; + float max = 0.495f; + gl.glBegin(GL2.GL_QUADS); + { + gl.glColor4f(0, 0, 0, 0.8f); + // top: right + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x + min, location.y + min, location.z - min); + gl.glVertex3f(location.x + max, location.y + min, location.z - min); + gl.glVertex3f(location.x + max, location.y + min, location.z + min); + // top: left + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + min, location.z - min); + gl.glVertex3f(location.x - max, location.y + min, location.z - min); + gl.glVertex3f(location.x - max, location.y + min, location.z + min); + // top: back + gl.glVertex3f(location.x + min, location.y + min, location.z - min); + gl.glVertex3f(location.x - min, location.y + min, location.z - min); + gl.glVertex3f(location.x - min, location.y + min, location.z - max); + gl.glVertex3f(location.x + min, location.y + min, location.z - max); + // top: front + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + min, location.z + max); + gl.glVertex3f(location.x + min, location.y + min, location.z + max); + // bottom: right + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x + min, location.y - min, location.z - min); + gl.glVertex3f(location.x + max, location.y - min, location.z - min); + gl.glVertex3f(location.x + max, location.y - min, location.z + min); + // bottom: left + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z - min); + gl.glVertex3f(location.x - max, location.y - min, location.z - min); + gl.glVertex3f(location.x - max, location.y - min, location.z + min); + // bottom: back + gl.glVertex3f(location.x + min, location.y - min, location.z - min); + gl.glVertex3f(location.x - min, location.y - min, location.z - min); + gl.glVertex3f(location.x - min, location.y - min, location.z - max); + gl.glVertex3f(location.x + min, location.y - min, location.z - max); + // bottom: front + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + max); + gl.glVertex3f(location.x + min, location.y - min, location.z + max); + // front: right + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x + max, location.y - min, location.z + min); + gl.glVertex3f(location.x + max, location.y + min, location.z + min); + // front: left + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - max, location.y - min, location.z + min); + gl.glVertex3f(location.x - max, location.y + min, location.z + min); + // front: bottom + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - max, location.z + min); + gl.glVertex3f(location.x + min, location.y - max, location.z + min); + // front: top + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + max, location.z + min); + gl.glVertex3f(location.x + min, location.y + max, location.z + min); + // back: right + gl.glVertex3f(location.x + min, location.y + min, location.z - min); + gl.glVertex3f(location.x + min, location.y - min, location.z - min); + gl.glVertex3f(location.x + max, location.y - min, location.z - min); + gl.glVertex3f(location.x + max, location.y + min, location.z - min); + // back: left + gl.glVertex3f(location.x - min, location.y + min, location.z - min); + gl.glVertex3f(location.x - min, location.y - min, location.z - min); + gl.glVertex3f(location.x - max, location.y - min, location.z - min); + gl.glVertex3f(location.x - max, location.y + min, location.z - min); + // back: bottom + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - max, location.z + min); + gl.glVertex3f(location.x + min, location.y - max, location.z + min); + // back: top + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + max, location.z + min); + gl.glVertex3f(location.x + min, location.y + max, location.z + min); + // left: back + gl.glVertex3f(location.x - min, location.y + min, location.z - min); + gl.glVertex3f(location.x - min, location.y - min, location.z - min); + gl.glVertex3f(location.x - min, location.y - min, location.z - max); + gl.glVertex3f(location.x - min, location.y + min, location.z - max); + // left: front + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + max); + gl.glVertex3f(location.x - min, location.y + min, location.z + max); + // left: top + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + min, location.z - min); + gl.glVertex3f(location.x - min, location.y + max, location.z - min); + gl.glVertex3f(location.x - min, location.y + max, location.z + min); + // left: bottom + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z - min); + gl.glVertex3f(location.x - min, location.y - max, location.z - min); + gl.glVertex3f(location.x - min, location.y - max, location.z + min); + // right: back + gl.glVertex3f(location.x + min, location.y + min, location.z - min); + gl.glVertex3f(location.x + min, location.y - min, location.z - min); + gl.glVertex3f(location.x + min, location.y - min, location.z - max); + gl.glVertex3f(location.x + min, location.y + min, location.z - max); + // right: front + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x + min, location.y - min, location.z + max); + gl.glVertex3f(location.x + min, location.y + min, location.z + max); + // right: top + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x + min, location.y + min, location.z - min); + gl.glVertex3f(location.x + min, location.y + max, location.z - min); + gl.glVertex3f(location.x + min, location.y + max, location.z + min); + // right: bottom + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x + min, location.y - min, location.z - min); + gl.glVertex3f(location.x + min, location.y - max, location.z - min); + gl.glVertex3f(location.x + min, location.y - max, location.z + min); + } + gl.glEnd(); } } diff --git a/src/ru/olamedia/olacraft/world/block/BlockRegistry.java b/src/ru/olamedia/olacraft/world/block/BlockRegistry.java index 19ccc94..ec9f9c1 100644 --- a/src/ru/olamedia/olacraft/world/block/BlockRegistry.java +++ b/src/ru/olamedia/olacraft/world/block/BlockRegistry.java @@ -23,16 +23,13 @@ public class BlockRegistry { return names.get(id); } - public int registerBlockType(@SuppressWarnings("rawtypes") Class type) { - if (type.isInstance(BlockType.class)) { - autoincrement++; - int id = autoincrement; - String classId = type.getName(); - names.put(id, classId); - // types.put(id, type); - return autoincrement; - } - return 0; + public int registerBlockType(BlockType type) { + autoincrement++; + int id = autoincrement; + String classId = type.getClass().getName(); + names.put(id, classId); + types.put(id, type); + return autoincrement; } public BlockRegistry getWorldRegistry() { diff --git a/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java index 6e2a86f..717c01f 100644 --- a/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java +++ b/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java @@ -2,6 +2,8 @@ package ru.olamedia.olacraft.world.blockTypes; import com.jogamp.opengl.util.texture.Texture; +import ru.olamedia.olacraft.world.block.BlockRegistry; +import ru.olamedia.olacraft.world.provider.WorldProvider; import ru.olamedia.texture.TextureManager; public abstract class AbstractBlockType implements BlockType { @@ -75,12 +77,13 @@ public abstract class AbstractBlockType implements BlockType { return TextureManager.get(this.getBackTextureFile()); } - public void register(){ + public void register(WorldProvider provider){ getBackTexture(); getBottomTexture(); getFrontTexture(); getLeftTexture(); getRightTexture(); getTopTexture(); + provider.getTypeRegistry().registerBlockType(this); } } diff --git a/src/ru/olamedia/olacraft/world/blockTypes/DirtBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/DirtBlockType.java new file mode 100644 index 0000000..a4e5dd7 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/DirtBlockType.java @@ -0,0 +1,23 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class DirtBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Gravel"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/dirt.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/dirt.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/StoneBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/StoneBlockType.java new file mode 100644 index 0000000..d2b3446 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/StoneBlockType.java @@ -0,0 +1,29 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class StoneBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Stone"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/terrain-cobb.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/terrain-cobb.png"; + } + + @Override + public String getFrontTextureFile() { + return "texture/terrain-cobb.png"; + } +} + diff --git a/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java b/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java index bad802f..d02999d 100644 --- a/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java +++ b/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java @@ -34,7 +34,8 @@ public class BlockSlice implements Iterator<Block> { } } } catch (ChunkUnavailableException e) { - e.printStackTrace(); + //e.printStackTrace(); + b.request(); } } return nearestBlock; diff --git a/src/ru/olamedia/olacraft/world/chunk/Chunk.java b/src/ru/olamedia/olacraft/world/chunk/Chunk.java index 9c0afb7..f390ebc 100644 --- a/src/ru/olamedia/olacraft/world/chunk/Chunk.java +++ b/src/ru/olamedia/olacraft/world/chunk/Chunk.java @@ -1,7 +1,8 @@ package ru.olamedia.olacraft.world.chunk; import ru.olamedia.geom.SimpleQuadMesh; -import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; +import ru.olamedia.olacraft.world.blockTypes.BlockType; +import ru.olamedia.olacraft.world.data.ChunkData; import ru.olamedia.olacraft.world.location.BlockLocation; import ru.olamedia.olacraft.world.location.ChunkLocation; import ru.olamedia.olacraft.world.provider.WorldProvider; @@ -9,6 +10,8 @@ import ru.olamedia.olacraft.world.provider.WorldProvider; public class Chunk extends BlockSlice { public boolean isMeshCostructed = false; public SimpleQuadMesh mesh; + public boolean usePrevMesh = false; + public SimpleQuadMesh prevMesh; public int visibleTop = 0; public int visibleBottom = 0; @@ -17,6 +20,25 @@ public class Chunk extends BlockSlice { public int visibleFront = 0; public int visibleBack = 0; + public void render() { + if (isMeshCostructed) { + mesh.joglRender(); + } else if (usePrevMesh) { + prevMesh.joglRender(); + } + } + + public void invalidate() { + if (null != mesh) { + prevMesh = mesh; + usePrevMesh = true; + if (null != mesh) { + mesh.restart(); + } + } + isMeshCostructed = false; + } + public Chunk(WorldProvider provider) { super(provider, 16, 16, 16); } @@ -93,32 +115,51 @@ public class Chunk extends BlockSlice { * @return the mesh */ public SimpleQuadMesh getMesh() { + if (!isAvailable()) { + return null; + } if (isMeshCostructed) { return mesh; } - if (offset.y > provider.getInfo().maxHeight) { - // isMeshCostructed = true; - // return null; + if (offset.y >= provider.getInfo().maxHeight) { + isMeshCostructed = true; + return null; } if (offset.y < provider.getInfo().minHeight) { - // isMeshCostructed = true; - // return null; + isMeshCostructed = true; + return null; } - if (null == mesh) { - mesh = new SimpleQuadMesh(14739); // unindexed + + if (null == mesh || mesh.restart) { + ChunkData data = provider.getChunk(offset.getChunkLocation()); + data.computeVisibility(provider); + // max 14739 + System.out.println(data.visibleCount + " vis"); + mesh = new SimpleQuadMesh(14739); + //mesh = new SimpleQuadMesh(Math.min(data.visibleCount * 6, 14739)); + mesh.start(); // 17x17x17 // vertices mesh.useColor(); mesh.useTexture(); // gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_FASTEST); // gl.glHint(GL2.GL_LINE_SMOOTH_HINT, GL2.GL_NICEST); - GrassBlockType grass = new GrassBlockType(); - for (int x = offset.x; x < offset.x + getWidth(); x++) { - for (int y = offset.y; y < offset.y + getHeight(); y++) { - for (int z = offset.z; z < offset.z + getDepth(); z++) { + BlockType grass; + for (int dx = 0; dx < 16; dx++) { + for (int dy = 0; dy < 16; dy++) { + for (int dz = 0; dz < 16; dz++) { + int x = offset.x + dx; + int y = offset.y + dy; + int z = offset.z + dz; + if (mesh.restart) { + return null; + } // try { - if (!isEmptyBlock(x, y, z)) { + int id = dx * 16 * 16 + dy * 16 + dz; + if (data.visible.get(id) && !data.emptyBlocks.get(id)) { + grass = provider.getTypeRegistry().getBlockType( + provider.getChunk((new BlockLocation(x, y, z)).getChunkLocation()).types[id]); mesh.setTranslation(x, y, z); // mesh.setColor4f(0, 1, 0, 1); float cbase = (float) (y / 200.0) * (float) (7.0 / 10.0); @@ -197,6 +238,7 @@ public class Chunk extends BlockSlice { } } mesh.endMesh(); + data.visible = null; isMeshCostructed = true; return null; } @@ -311,4 +353,8 @@ public class Chunk extends BlockSlice { public void setLocation(ChunkLocation location) { setLocation(location.getBlockLocation().x, location.getBlockLocation().y, location.getBlockLocation().z); } + + public boolean inWorldRange() { + return (offset.y + 16 < provider.getInfo().maxHeight) && (offset.y > provider.getInfo().minHeight); + } } diff --git a/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java b/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java index d362199..e823b2f 100644 --- a/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java +++ b/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java @@ -4,7 +4,7 @@ import java.util.concurrent.ArrayBlockingQueue; public class ChunkMeshBulder extends Thread { public static ChunkMeshBulder instance = new ChunkMeshBulder("Mesh builder"); - private ArrayBlockingQueue<Chunk> chunks = new ArrayBlockingQueue<Chunk>(16); + private ArrayBlockingQueue<Chunk> chunks = new ArrayBlockingQueue<Chunk>(256); public ChunkMeshBulder(String name) { super(name); @@ -36,6 +36,9 @@ public class ChunkMeshBulder extends Thread { // main loop try { tick(); + if (chunks.isEmpty()){ + Thread.sleep(50); + } // Thread.sleep(10); // or wait/join etc } catch (InterruptedException ex) { // cleanup here diff --git a/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java b/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java index d0307bb..14e2c1f 100644 --- a/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java +++ b/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java @@ -21,20 +21,41 @@ public class ChunkSlice { } protected HashMap<String, Chunk> chunks = new HashMap<String, Chunk>(); + protected HashMap<Integer, HashMap<Integer, HashMap<Integer, Chunk>>> iChunks = new HashMap<Integer, HashMap<Integer, HashMap<Integer, Chunk>>>(); public Chunk getChunk(ChunkLocation location) { - int x = location.x; - int y = location.y; - int z = location.z; - String key = x + ";" + y + ";" + z; - if (chunks.containsKey(key)) { - return chunks.get(key); + // int x = location.x; + // int y = location.y; + // int z = location.z; + // String key = x + ";" + y + ";" + z; + if (iChunks.containsKey(location.x)) { + if (iChunks.get(location.x).containsKey(location.y)) { + if (iChunks.get(location.x).get(location.y).containsKey(location.z)) { + return iChunks.get(location.x).get(location.y).get(location.z); + } else { + + } + } else { + iChunks.get(location.x).put(location.y, new HashMap<Integer, Chunk>()); + } } else { - Chunk chunk = new Chunk(provider); - chunk.setLocation(location); - chunks.put(key, chunk); - return chunk; + iChunks.put(location.x, new HashMap<Integer, HashMap<Integer, Chunk>>()); + iChunks.get(location.x).put(location.y, new HashMap<Integer, Chunk>()); } + + Chunk chunk = new Chunk(provider); + chunk.setLocation(location); + // chunks.put(key, chunk); + iChunks.get(location.x).get(location.y).put(location.z, chunk); + return chunk; + // if (chunks.containsKey(key)) { + // return chunks.get(key); + // } else { + // Chunk chunk = new Chunk(provider); + // chunk.setLocation(location); + // chunks.put(key, chunk); + // return chunk; + // } } /** @@ -108,6 +129,7 @@ public class ChunkSlice { public int getZ() { return offset.z; } + public void setLocation(ChunkLocation chunkOffset) { offset = chunkOffset; } diff --git a/src/ru/olamedia/olacraft/world/data/ChunkData.java b/src/ru/olamedia/olacraft/world/data/ChunkData.java index a6b9f34..42f7811 100644 --- a/src/ru/olamedia/olacraft/world/data/ChunkData.java +++ b/src/ru/olamedia/olacraft/world/data/ChunkData.java @@ -3,9 +3,11 @@ package ru.olamedia.olacraft.world.data; import java.io.Serializable; import ru.olamedia.math.OpenBitSet; +import ru.olamedia.olacraft.world.blockTypes.BlockType; import ru.olamedia.olacraft.world.chunk.Chunk; import ru.olamedia.olacraft.world.location.BlockLocation; import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.provider.WorldProvider; public class ChunkData implements Serializable { private static final long serialVersionUID = -5704237444737895501L; @@ -13,17 +15,160 @@ public class ChunkData implements Serializable { public static transient int SIZE = 4096; // private boolean[] notEmpty = new boolean[SIZE]; public OpenBitSet emptyBlocks = new OpenBitSet(4096); + public int visibleCount = 0; + public OpenBitSet visible = null; // fast precomputed + // visibility (true if + // any side is open) + //public OpenBitSet sunlight = new OpenBitSet(65536); + public byte[] types = new byte[4096]; public int notEmptyCount = 0; + public boolean visibilityPrecomputed = false; // public transient int[] type = new int[SIZE]; public ChunkData() { } + private void setVisible(int x, int y, int z) { + if (x < 0 || x > 15 || y < 0 || y > 15 || z < 0 || z > 15) { + return; + } + int id = x * 16 * 16 + y * 16 + z; + if (!visible.get(id)){ + visibleCount++; + } + visible.set(id); + } + + private void setInvisible(int x, int y, int z) { + if (x < 0 || x > 15 || y < 0 || y > 15 || z < 0 || z > 15) { + return; + } + int id = x * 16 * 16 + y * 16 + z; + if (visible.get(id)){ + visibleCount--; + } + visible.clear(id); + } + + public void computeVisibility(WorldProvider provider) { + visible = new OpenBitSet(4096); + visibleCount = 0; + precomputeVisibility(); + computeVisibility(provider.getChunk(location.getLeft()), provider.getChunk(location.getRight()), + provider.getChunk(location.getTop()), provider.getChunk(location.getBottom()), + provider.getChunk(location.getFront()), provider.getChunk(location.getBack())); + } + + public void computeVisibility(ChunkData left, ChunkData right, ChunkData top, ChunkData bottom, ChunkData front, + ChunkData back) { + // compute left/right + int x, y, z, id; + for (y = 0; y <= 15; y++) { + for (z = 0; z <= 15; z++) { + x = 15; + id = x * 16 * 16 + y * 16 + z; + if (left.emptyBlocks.get(id)) { + x = 0; + setVisible(x, y, z); + } + x = 0; + id = x * 16 * 16 + y * 16 + z; + if (right.emptyBlocks.get(id)) { + x = 15; + setVisible(x, y, z); + } + } + } + // top/bottom + for (x = 0; x <= 15; x++) { + for (z = 0; z <= 15; z++) { + y = 15; + id = x * 16 * 16 + y * 16 + z; + if (bottom.emptyBlocks.get(id)) { + y = 0; + setVisible(x, y, z); + } + y = 0; + id = x * 16 * 16 + y * 16 + z; + if (top.emptyBlocks.get(id)) { + y = 15; + setVisible(x, y, z); + } + } + } + // front/back + for (x = 0; x <= 15; x++) { + for (y = 0; y <= 15; y++) { + z = 15; + id = x * 16 * 16 + y * 16 + z; + if (back.emptyBlocks.get(id)) { + z = 0; + setVisible(x, y, z); + } + z = 0; + id = x * 16 * 16 + y * 16 + z; + if (front.emptyBlocks.get(id)) { + z = 15; + setVisible(x, y, z); + } + } + } + } + + /** + * Compute visibility ("visible" if any side have non-opaque neighbor) + * Leaving side blocks invisible. Use computeVisibility(WorldProvider) to compute visibility of side blocks + */ + public void precomputeVisibility() { + // first pass, make all blocks invisible, except side blocks + for (int x = 0; x <= 15; x++) { + for (int y = 0; y <= 15; y++) { + for (int z = 0; z <= 15; z++) { + // if (x == 0 || x == 15 || y == 0 || y == 15 || z == 0 || z + // == 15) { + // setVisible(x, y, z); + // } else { + // setInvisible(x, y, z); + // } + setInvisible(x, y, z); + } + } + } + // second pass, make some blocks visible + for (int x = 0; x <= 15; x++) { + for (int y = 0; y <= 15; y++) { + for (int z = 0; z <= 15; z++) { + int id = x * 16 * 16 + y * 16 + z; + if (emptyBlocks.get(id)) { + setVisible(x - 1, y, z); + setVisible(x + 1, y, z); + setVisible(x, y - 1, z); + setVisible(x, y + 1, z); + setVisible(x, y, z - 1); + setVisible(x, y, z + 1); + } + } + } + } + visibilityPrecomputed = true; + } + public void compact() { if (emptyBlocks.cardinality() == 0) { - emptyBlocks = null; + // emptyBlocks = null; + } + } + + public BlockType getType(BlockLocation blockLocation, WorldProvider provider) { + if (emptyBlocks == null) { + return null; + } + int id = Chunk.in(blockLocation.x) * 16 * 16 + Chunk.in(blockLocation.y) * 16 + Chunk.in(blockLocation.z); + if (isEmpty(id)) { + return null; } + return provider.getBlockTypeById(types[id]); } public boolean isEmpty(BlockLocation blockLocation) { diff --git a/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java index 9ba9496..1e6c0c1 100644 --- a/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java +++ b/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java @@ -1,6 +1,9 @@ package ru.olamedia.olacraft.world.dataProvider; import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import ru.olamedia.olacraft.world.data.RegionData; import ru.olamedia.olacraft.world.location.RegionLocation; @@ -8,6 +11,7 @@ import ru.olamedia.olacraft.world.location.RegionLocation; public class CachedChunkDataProvider extends AbstractChunkDataProvider { private AbstractChunkDataProvider provider; private HashMap<String, RegionData> regionMap = new HashMap<String, RegionData>(); + private ConcurrentHashMap<String, Integer> ticks = new ConcurrentHashMap<String, Integer>(); public CachedChunkDataProvider(AbstractChunkDataProvider provider) { this.provider = provider; @@ -21,6 +25,24 @@ public class CachedChunkDataProvider extends AbstractChunkDataProvider { } } + @SuppressWarnings("unused") + private void tick(String key) { + ticks.put(key, 0); + gc(); + } + + private void gc() { + Iterator<String> keys = ticks.keySet().iterator(); + while (keys.hasNext()) { + String key = keys.next(); + ticks.put(key, ticks.get(key) + 1); + if (ticks.get(key) > 30) { + ticks.remove(key); + regionMap.remove(key); + } + } + } + @Override public boolean isRegionAvailable(RegionLocation regionLocation) { String key = regionLocation.toString();// regionLocation.x + "-" + @@ -44,6 +66,7 @@ public class CachedChunkDataProvider extends AbstractChunkDataProvider { @Override public RegionData getRegion(RegionLocation regionLocation) { String key = regionLocation.toString(); + // tick(key); if (regionMap.containsKey(key)) { return regionMap.get(key); } else { diff --git a/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java index cd48071..0c52ced 100644 --- a/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java +++ b/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java @@ -19,6 +19,7 @@ public class RemoteChunkDataProvider extends AbstractChunkDataProvider implement private GameClient client; private HashMap<String, RegionData> map = new HashMap<String, RegionData>(); private List<String> loading = new ArrayList<String>(); + private List<RegionLocation> queue = new ArrayList<RegionLocation>(); public RemoteChunkDataProvider(GameClient client) { this.client = client; @@ -36,7 +37,7 @@ public class RemoteChunkDataProvider extends AbstractChunkDataProvider implement @Override public void loadRegion(RegionLocation regionLocation) { String key = regionLocation.toString(); - if (!loading.contains(key)) { + if (loading.isEmpty() && !loading.contains(key)) { debug("loadRegion(" + key + ")"); loading.add(key); client.send(new GetRegionPacket(regionLocation)); diff --git a/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java b/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java index 05fc067..79ac898 100644 --- a/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java +++ b/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java @@ -1,5 +1,6 @@ package ru.olamedia.olacraft.world.generator; +import ru.olamedia.olacraft.world.chunk.Chunk; import ru.olamedia.olacraft.world.data.ChunkData; import ru.olamedia.olacraft.world.data.HeightMap; import ru.olamedia.olacraft.world.data.RegionData; @@ -68,7 +69,10 @@ public class RegionGenerator { // System.out.println("not empty, height: " // + height); } + int id = Chunk.in(blockOffset.x) * 16 * 16 + Chunk.in(blockOffset.y) * 16 + + Chunk.in(blockOffset.z); chunk.setEmpty(blockOffset, false); + chunk.types[id] = (byte) (1 + Math.random() * 4); } } } diff --git a/src/ru/olamedia/olacraft/world/location/BlockLocation.java b/src/ru/olamedia/olacraft/world/location/BlockLocation.java index b104bad..9639ac1 100644 --- a/src/ru/olamedia/olacraft/world/location/BlockLocation.java +++ b/src/ru/olamedia/olacraft/world/location/BlockLocation.java @@ -13,12 +13,49 @@ public class BlockLocation implements Serializable { public BlockLocation() { } + public boolean isChunkEdge() { + int cx = Chunk.in(x); + int cy = Chunk.in(y); + int cz = Chunk.in(z); + return (cx == 0 || cy == 0 || cz == 0 || cx == 15 || cy == 15 || cz == 15); + } + + public boolean isChunkLeftEdge() { + return Chunk.in(x) == 0; + } + + public boolean isChunkRightEdge() { + return Chunk.in(x) == 15; + } + + public boolean isChunkTopEdge() { + return Chunk.in(y) == 15; + } + + public boolean isChunkBottomEdge() { + return Chunk.in(y) == 0; + } + + public boolean isChunkFrontEdge() { + return Chunk.in(z) == 15; + } + + public boolean isChunkBackEdge() { + return Chunk.in(z) == 0; + } + public BlockLocation(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } + public BlockLocation(float x, float y, float z) { + this.x = (int) x; + this.y = (int) y; + this.z = (int) z; + } + public ChunkLocation getChunkLocation() { return new ChunkLocation(Chunk.v(x), Chunk.v(y + 128), Chunk.v(z)); } diff --git a/src/ru/olamedia/olacraft/world/location/ChunkLocation.java b/src/ru/olamedia/olacraft/world/location/ChunkLocation.java index a772c6d..439b9be 100644 --- a/src/ru/olamedia/olacraft/world/location/ChunkLocation.java +++ b/src/ru/olamedia/olacraft/world/location/ChunkLocation.java @@ -17,6 +17,12 @@ public class ChunkLocation implements Serializable { this.z = z; } + public ChunkLocation(ChunkLocation loc) { + this.x = loc.x; + this.y = loc.y; + this.z = loc.z; + } + public int x; public int y; public int z; @@ -42,4 +48,32 @@ public class ChunkLocation implements Serializable { public BlockLocation getBlockLocation() { return new BlockLocation(Chunk.rev(x), Chunk.rev(y) - 128, Chunk.rev(z)); } + + public ChunkLocation getNeighbor(int dx, int dy, int dz) { + return new ChunkLocation(x + dx, y + dy, z + dz); + } + + public ChunkLocation getLeft() { + return getNeighbor(-1, 0, 0); + } + + public ChunkLocation getRight() { + return getNeighbor(1, 0, 0); + } + + public ChunkLocation getTop() { + return getNeighbor(0, 1, 0); + } + + public ChunkLocation getBottom() { + return getNeighbor(0, -1, 0); + } + + public ChunkLocation getBack() { + return getNeighbor(0, 0, -1); + } + + public ChunkLocation getFront() { + return getNeighbor(0, 0, 1); + } } diff --git a/src/ru/olamedia/olacraft/world/provider/WorldProvider.java b/src/ru/olamedia/olacraft/world/provider/WorldProvider.java index 9e76d1a..7471b52 100644 --- a/src/ru/olamedia/olacraft/world/provider/WorldProvider.java +++ b/src/ru/olamedia/olacraft/world/provider/WorldProvider.java @@ -3,7 +3,9 @@ package ru.olamedia.olacraft.world.provider; import ru.olamedia.olacraft.game.SpawnLocation; import ru.olamedia.olacraft.world.WorldInfo; import ru.olamedia.olacraft.world.block.Block; -import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.block.BlockRegistry; +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; +import ru.olamedia.olacraft.world.blockTypes.BlockType; import ru.olamedia.olacraft.world.chunk.ChunkUnavailableException; import ru.olamedia.olacraft.world.data.ChunkData; import ru.olamedia.olacraft.world.data.RegionData; @@ -14,11 +16,16 @@ import ru.olamedia.olacraft.world.location.RegionLocation; public class WorldProvider { private WorldInfo info = new WorldInfo(); + private BlockRegistry typeRegistry = new BlockRegistry(); private AbstractChunkDataProvider dataProvider; public WorldInfo getInfo() { return info; } + + public BlockRegistry getTypeRegistry(){ + return typeRegistry; + } public void setInfo(WorldInfo worldInfo) { info = worldInfo; @@ -126,11 +133,14 @@ public class WorldProvider { } public Block getBlock(int x, int y, int z) { - BlockLocation blockLocation = new BlockLocation(x, y, z); return new Block(this, x, y, z); } public ChunkData getChunk(ChunkLocation chunkLocation) { return dataProvider.getChunk(chunkLocation); } + + public BlockType getBlockTypeById(int id) { + return typeRegistry.getBlockType(id); + } } |