diff options
Diffstat (limited to 'src/ru/olamedia/olacraft/world')
49 files changed, 2554 insertions, 0 deletions
diff --git a/src/ru/olamedia/olacraft/world/World.java b/src/ru/olamedia/olacraft/world/World.java new file mode 100644 index 0000000..e3d25f2 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/World.java @@ -0,0 +1,12 @@ +package ru.olamedia.olacraft.world; + +import ru.olamedia.olacraft.world.block.BlockRegistry; +import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; + +public class World { + private BlockRegistry blockRegistry; + public void setup() { + blockRegistry = new BlockRegistry(); + blockRegistry.registerBlockType(GrassBlockType.class); + } +} diff --git a/src/ru/olamedia/olacraft/world/WorldInfo.java b/src/ru/olamedia/olacraft/world/WorldInfo.java new file mode 100644 index 0000000..797339f --- /dev/null +++ b/src/ru/olamedia/olacraft/world/WorldInfo.java @@ -0,0 +1,11 @@ +package ru.olamedia.olacraft.world; + +import java.io.Serializable; + +public class WorldInfo implements Serializable { + private static final long serialVersionUID = -3669317489158639456L; + public String name = "world"; + public int minHeight = -128; + public int maxHeight = 127; + public float gravity = 9.81f; +} diff --git a/src/ru/olamedia/olacraft/world/block/Block.java b/src/ru/olamedia/olacraft/world/block/Block.java new file mode 100644 index 0000000..a48c9df --- /dev/null +++ b/src/ru/olamedia/olacraft/world/block/Block.java @@ -0,0 +1,111 @@ +package ru.olamedia.olacraft.world.block; + +import ru.olamedia.olacraft.world.blockTypes.BlockType; +import ru.olamedia.olacraft.world.blockTypes.EmptyBlockType; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class Block { + private WorldProvider provider; + private int x; + private int y; + private int z; + + /** + * Inventory block + */ + public Block() { + this.provider = null; + this.x = 0; + this.y = 0; + this.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; + } + + public Block(WorldProvider worldProvider, int x, int y, int z) { + putIntoWorld(worldProvider, x, y, z); + } + + /** + * @return the x + */ + public int getX() { + return x; + } + + /** + * @param x + * the x to set + */ + public void setX(int x) { + this.x = x; + } + + /** + * @return the y + */ + public int getY() { + return y; + } + + /** + * @param y + * the y to set + */ + public void setY(int y) { + this.y = y; + } + + /** + * @return the z + */ + public int getZ() { + return z; + } + + /** + * @param z + * the z to set + */ + public void setZ(int z) { + this.z = z; + } + + public boolean isEmpty() { + return provider.isEmptyBlock(x, y, z); + } + + public Block getNeighbor(int dx, int dy, int dz) { + return new Block(provider, x + dx, y + dy, z + dz); + } + + public Block[] getNeighbors() { + return new Block[] { + // + getNeighbor(1, 0, 0),// + getNeighbor(0, 1, 0),// + getNeighbor(0, 0, 1),// + getNeighbor(-1, 0, 0),// + getNeighbor(0, -1, 0),// + getNeighbor(0, 0, -1),// + }; + } + + private BlockType type; + + public void setType(BlockType type) { + this.type = type; + } + + public BlockType getType() { + if (null == type) { + type = new EmptyBlockType(); + } + return type; + } +} diff --git a/src/ru/olamedia/olacraft/world/block/BlockRegistry.java b/src/ru/olamedia/olacraft/world/block/BlockRegistry.java new file mode 100644 index 0000000..19ccc94 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/block/BlockRegistry.java @@ -0,0 +1,46 @@ +package ru.olamedia.olacraft.world.block; + +import java.util.HashMap; + +import ru.olamedia.olacraft.world.blockTypes.BlockType; + +public class BlockRegistry { + + private HashMap<Integer, String> names = new HashMap<Integer, String>(); + private HashMap<Integer, BlockType> types = new HashMap<Integer, BlockType>(); + private int autoincrement = 0; + + private BlockRegistry worldRegistry; + + public BlockRegistry() { + } + + public BlockType getBlockType(int id) { + return types.get(id); + } + + public String getBlockHumanId(int id) { + 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 BlockRegistry getWorldRegistry() { + return worldRegistry; + } + + public void setWorldRegistry(BlockRegistry worldRegistry) { + this.worldRegistry = worldRegistry; + } + +} diff --git a/src/ru/olamedia/olacraft/world/block/package-info.java b/src/ru/olamedia/olacraft/world/block/package-info.java new file mode 100644 index 0000000..0924926 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/block/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.block;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/blockStack/BlockStack.java b/src/ru/olamedia/olacraft/world/blockStack/BlockStack.java new file mode 100644 index 0000000..57258ef --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockStack/BlockStack.java @@ -0,0 +1,63 @@ +package ru.olamedia.olacraft.world.blockStack; + +import ru.olamedia.olacraft.world.block.Block; + +public class BlockStack { + public Block block; + public int count; + + public BlockStack(Block block, int count) { + this.block = block; + this.count = count; + } + + public BlockStack get() { + return get(1); + } + + public BlockStack get(int getcount) { + int c = 0; + if (count >= getcount) { + c = getcount; + count -= getcount; + } else { + c = count; + count = 0; + } + return new BlockStack(block, c); + } + + public BlockStack getAll() { + int c = count; + count = 0; + return new BlockStack(block, c); + } + + /** + * + * @return Remaining BlockStack + */ + public BlockStack putStack(BlockStack stack) { + + if (block.getType() == stack.block.getType()) { + int max = block.getType().getMaxStack(); + // Stack + int total = count + stack.count; + if (total < max) { + count = total; + return new BlockStack(block, 0); + } else { + BlockStack remains = new BlockStack(block, total - max); + count = max; + return remains; + } + } else { + // Replace + BlockStack remains = new BlockStack(block, count); + block = stack.block; + count = stack.count; + return remains; + } + } + +} diff --git a/src/ru/olamedia/olacraft/world/blockStack/package-info.java b/src/ru/olamedia/olacraft/world/blockStack/package-info.java new file mode 100644 index 0000000..933dc87 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockStack/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.blockStack;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java new file mode 100644 index 0000000..6e2a86f --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java @@ -0,0 +1,86 @@ +package ru.olamedia.olacraft.world.blockTypes; + +import com.jogamp.opengl.util.texture.Texture; + +import ru.olamedia.texture.TextureManager; + +public abstract class AbstractBlockType implements BlockType { + + @Override + abstract public String getName(); + + @Override + public int getMaxStack() { + return 64; + } + + @Override + abstract public String getStackTextureFile(); + + @Override + abstract public String getTopTextureFile(); + + @Override + public String getBottomTextureFile() { + return this.getTopTextureFile(); + } + + @Override + public String getLeftTextureFile() { + return this.getFrontTextureFile(); + } + + @Override + public String getRightTextureFile() { + return this.getFrontTextureFile(); + } + + @Override + public String getFrontTextureFile() { + return this.getTopTextureFile(); + } + + @Override + public String getBackTextureFile() { + return this.getFrontTextureFile(); + } + + @Override + public Texture getTopTexture() { + return TextureManager.get(this.getTopTextureFile()); + } + + @Override + public Texture getBottomTexture() { + return TextureManager.get(this.getBottomTextureFile()); + } + + @Override + public Texture getLeftTexture() { + return TextureManager.get(this.getLeftTextureFile()); + } + + @Override + public Texture getRightTexture() { + return TextureManager.get(this.getRightTextureFile()); + } + + @Override + public Texture getFrontTexture() { + return TextureManager.get(this.getFrontTextureFile()); + } + + @Override + public Texture getBackTexture() { + return TextureManager.get(this.getBackTextureFile()); + } + + public void register(){ + getBackTexture(); + getBottomTexture(); + getFrontTexture(); + getLeftTexture(); + getRightTexture(); + getTopTexture(); + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java new file mode 100644 index 0000000..0bda2eb --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java @@ -0,0 +1,21 @@ +package ru.olamedia.olacraft.world.blockTypes; + +import com.jogamp.opengl.util.texture.Texture; + +public interface BlockType { + public String getName(); + public int getMaxStack(); + public String getStackTextureFile(); + public String getTopTextureFile(); + public String getBottomTextureFile(); + public String getLeftTextureFile(); + public String getRightTextureFile(); + public String getFrontTextureFile(); + public String getBackTextureFile(); + public Texture getTopTexture(); + public Texture getBottomTexture(); + public Texture getLeftTexture(); + public Texture getRightTexture(); + public Texture getFrontTexture(); + public Texture getBackTexture(); +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java new file mode 100644 index 0000000..4073356 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java @@ -0,0 +1,23 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class EmptyBlockType extends AbstractBlockType { + @Override + public String getName() { + return ""; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/empty.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/empty.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java new file mode 100644 index 0000000..816b283 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java @@ -0,0 +1,28 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class GrassBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Grass"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/terrain-grassdarkgreen.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/terrain-grassdarkgreen.png"; + } + + @Override + public String getFrontTextureFile() { + return "texture/terrain-glong-darkgreen-dirt.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java new file mode 100644 index 0000000..354d383 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java @@ -0,0 +1,23 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class GravelBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Gravel"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/gravel.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/gravel.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/package-info.java b/src/ru/olamedia/olacraft/world/blockTypes/package-info.java new file mode 100644 index 0000000..a49dda8 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.blockTypes;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java b/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java new file mode 100644 index 0000000..ca4c92a --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java @@ -0,0 +1,164 @@ +package ru.olamedia.olacraft.world.chunk; + +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class BlockSlice { + protected WorldProvider provider; + protected int leftX; + protected int bottomY; + protected int backZ; + protected int width; + protected int height; + protected int depth; + + protected ChunkSlice chunkSlice; + + // Memory leak: + //protected int[][] highest = new int[256][256]; + + public void invalidateCache(){ + //highest = new int[256][256]; + } + +/* public int getHighest(int blockX, int blockZ) { + if (highest[blockX - leftX][blockZ - backZ] > 0){ + return highest[blockX - leftX][blockZ - backZ]; + } + for (int y = 0; y < 128; y++) { + if (provider.isEmptyBlock(blockX, y, blockZ)){ + highest[blockX - leftX][blockZ - backZ] = y; + return y; + } + } + return 0; + }*/ + + /** + * + * @param provider + * @param width + * (blocks) + * @param height + * (blocks) + * @param depth + * (blocks) + */ + public BlockSlice(WorldProvider provider, int width, int height, int depth) { + this.provider = provider; + this.width = width; + this.height = height; + this.depth = depth; + } + + public ChunkSlice getChunkSlice() { + if (null == chunkSlice) { + chunkSlice = new ChunkSlice(provider, width / 16, height / 16, depth / 16); + } + int x = Chunk.v(leftX); + int y = Chunk.v(bottomY); + int z = Chunk.v(backZ); + chunkSlice.setLocation(x, y, z); + return chunkSlice; + } + + public int getTotalBlocks() { + return getWidth() * getHeight() * getDepth(); + } + + /** + * @return the width (blocks) + */ + public int getWidth() { + return width; + } + + /** + * @param width + * (blocks) + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * @return the height (blocks) + */ + public int getHeight() { + return height; + } + + /** + * @param height + * (blocks) + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * @return the depth (blocks) + */ + public int getDepth() { + return depth; + } + + /** + * @param depth + * (blocks) + */ + public void setDepth(int depth) { + this.depth = depth; + } + + /** + * + * @param x + * (blocks) + * @param y + * (blocks) + * @param z + * (blocks) + */ + public void setLocation(int x, int y, int z) { + if (x != leftX || y != bottomY || z != backZ){ + invalidateCache(); + } + leftX = x; + bottomY = y; + backZ = z; + } + + /** + * + * @param x + * (blocks) + * @param y + * (blocks) + * @param z + * (blocks) + */ + public void setCenter(int x, int y, int z) { + setLocation(x - width / 2, y - height / 2, z - depth / 2); + } + + /** + * @return the left x (blocks) + */ + public int getX() { + return leftX; + } + + /** + * @return the bottom y (blocks) + */ + public int getY() { + return bottomY; + } + + /** + * @return the back z (blocks) + */ + public int getZ() { + return backZ; + } +} diff --git a/src/ru/olamedia/olacraft/world/chunk/Chunk.java b/src/ru/olamedia/olacraft/world/chunk/Chunk.java new file mode 100644 index 0000000..ca2d4bf --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/Chunk.java @@ -0,0 +1,290 @@ +package ru.olamedia.olacraft.world.chunk; + +import ru.olamedia.geom.SimpleQuadMesh; +import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class Chunk extends BlockSlice { + public boolean isMeshCostructed = false; + public SimpleQuadMesh mesh; + + public int visibleTop = 0; + public int visibleBottom = 0; + public int visibleLeft = 0; + public int visibleRight = 0; + public int visibleFront = 0; + public int visibleBack = 0; + + public Chunk(WorldProvider provider) { + super(provider, 16, 16, 16); + } + + /** + * Convert block coordinate into chunk coordinate + * + * @param v + * block coordinate along one axis + * @return + */ + public static int v(int v) { + if (v >= 0) { + return v / 16; + } else { + return (v + 1) / 16 - 1; + } + } + + /** + * Convert block coordinate into block position inside of chunk + * + * @param v + * block coordinate along one axis + * @return + */ + public static int in(int v) { + int tmp = v - v(v) * 16; + return tmp >= 0 ? tmp : 16 + tmp; // block location minus chunk base + // location + // (lower-left-back corner) + // if (v >= 0) { + // return v % 16; + // } else { + // int in = v + 1; // shift up so -1 will be 0 + // in %= 16; // get remaining -15..0 + // in += 15; // revert 0..15 + // return in; + // } + } + + public void setMeshColor(SimpleQuadMesh mesh, int x, int y, int z, boolean isSide) { + float level = 1f;// ((float) getProvider().getBlockLightLevel(x, y, z) - + // (isSide ? 2 : 0)) / 15.0f; + mesh.setColor4f(level, level, level, 1); + if (y < 0) { + mesh.setColor4f(0, 0, 1, 1); + } else if (y > 30) { + mesh.setColor4f(1, 1, 1, 1); + } else { + mesh.setColor4f(1, 1, 0, 1); + } + } + + /** + * @return the mesh + */ + public SimpleQuadMesh getMesh() { + if (isMeshCostructed) { + return mesh; + } + if (getY() > provider.getInfo().maxHeight) { + isMeshCostructed = true; + return null; + } + if (getY() < provider.getInfo().minHeight) { + isMeshCostructed = true; + return null; + } + if (null == mesh) { + mesh = new SimpleQuadMesh(14739); // unindexed + // 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 = getX(); x < getX() + getWidth(); x++) { + for (int y = getY(); y < getY() + getHeight(); y++) { + for (int z = getZ(); z < getZ() + getDepth(); z++) { + // + + if (!isEmptyBlock(x, y, z)) { + mesh.setTranslation(x, y, z); + // mesh.setColor4f(0, 1, 0, 1); + float cbase = (float) (y / 200.0) * (float) (7.0 / 10.0); + if (cbase > 9 / 10) { + cbase = (float) (9.0 / 10.0); + } + // cbase = (float) (9.0 / 10.0); + float cred, cgreen, cblue; + // cbase; + cred = cgreen = cblue = getLightLevel256(x, y, z); + if (x == 1) { + mesh.setColor4f(1, 0, 0, 1); + // red to the right + } + if (x == 0 || z == 0) { + if (y == 6) { + mesh.setColor4f(1, 0, 0, 1); + } else if (y % 2 == 0) { + mesh.setColor4f(1, 0, 1, 1); + } else { + mesh.setColor4f(1, 1, 0, 1); + } + } + if (z == 1) { + mesh.setColor4f(0, 0, 1, 1); + // blue to the bottom + } + if (renderBottom(x, y, z)) { + setMeshColor(mesh, x, y - 1, z, false); + mesh.setTexture(grass.getBottomTexture()); + mesh.addBottomQuad(); + visibleBottom++; + } + if (renderTop(x, y, z)) { + if (x == 15 || z == 15) { + // debug: show through.. + } else { + setMeshColor(mesh, x, y + 1, z, false); + mesh.setTexture(grass.getTopTexture()); + mesh.addTopQuad(); + } + visibleTop++; + } + if (renderLeft(x, y, z)) { + setMeshColor(mesh, x - 1, y, z, true); + mesh.setTexture(grass.getLeftTexture()); + mesh.addLeftQuad(); + visibleLeft++; + } + if (renderRight(x, y, z)) { + setMeshColor(mesh, x + 1, y, z, true); + mesh.setTexture(grass.getRightTexture()); + mesh.addRightQuad(); + visibleRight++; + } + if (renderBack(x, y, z)) { + setMeshColor(mesh, x, y, z - 1, true); + mesh.setTexture(grass.getBackTexture()); + mesh.addBackQuad(); + visibleBack++; + } + if (renderFront(x, y, z)) { + setMeshColor(mesh, x, y, z + 1, true); + mesh.setTexture(grass.getFrontTexture()); + mesh.addFrontQuad(); + visibleFront++; + } + } + } + } + } + mesh.endMesh(); + isMeshCostructed = true; + return null; + } + return mesh; + } + + /** + * @param mesh + * the mesh to set + */ + public void setMesh(SimpleQuadMesh mesh) { + this.mesh = mesh; + } + + public boolean isEmpty() { + // MUST BE LOADED + return provider.getChunk(getBlockLocation().getChunkLocation()).isEmpty(); + } + + private BlockLocation getBlockLocation() { + return new BlockLocation(getX(), getY(), getZ()); + } + + public boolean isAvailable() { + return provider.isChunkAvailable(getBlockLocation().getChunkLocation()); + } + + public boolean isNeighborsAvailable() { + int x = Chunk.v(getX()); + int y = Chunk.v(getY()); + int z = Chunk.v(getZ()); + return provider.isChunkAvailable(new ChunkLocation(x - 1, y, z)) + && provider.isChunkAvailable(new ChunkLocation(x + 1, y, z)) + && provider.isChunkAvailable(new ChunkLocation(x, y - 1, z)) + && provider.isChunkAvailable(new ChunkLocation(x, y + 1, z)) + && provider.isChunkAvailable(new ChunkLocation(x, y, z - 1)) + && provider.isChunkAvailable(new ChunkLocation(x, y, z + 1)); + } + + public void requestNeighbors() { + int x = Chunk.v(getX()); + int y = Chunk.v(getY()); + int z = Chunk.v(getZ()); + if (!provider.isChunkAvailable(new ChunkLocation(x - 1, y, z))) { + provider.loadChunk(new ChunkLocation(x - 1, y, z)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x + 1, y, z))) { + provider.loadChunk(new ChunkLocation(x + 1, y, z)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x, y - 1, z))) { + provider.loadChunk(new ChunkLocation(x, y - 1, z)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x, y + 1, z))) { + provider.loadChunk(new ChunkLocation(x, y + 1, z)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x, y, z - 1))) { + provider.loadChunk(new ChunkLocation(x, y, z - 1)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x, y, z + 1))) { + provider.loadChunk(new ChunkLocation(x, y, z + 1)); + } + } + + public void request() { + BlockLocation blockLocation = new BlockLocation(getX(), getY(), getZ()); + // System.out.println("provider.requestChunk(" + + // blockLocation.getRegionLocation() + blockLocation.getChunkLocation() + // + ")"); + provider.loadChunk(blockLocation.getChunkLocation()); + } + + // public BlockType getBlockType(int x, int y, int z) { + // return provider.getBlockType(int x, int y, int z); + // } + + public boolean isEmptyBlock(int x, int y, int z) { + return provider.isEmptyBlock(x, y, z); + } + + public float getLightLevel256(int x, int y, int z) { + return ((float) getLightLevel(x, y, z)) / 15.0f;// * 255.0f + } + + public int getLightLevel(int x, int y, int z) { + return 15; + } + + public boolean renderBottom(int x, int y, int z) { + return provider.renderBottom(x, y, z); + } + + public boolean renderTop(int x, int y, int z) { + return provider.renderTop(x, y, z); + } + + public boolean renderLeft(int x, int y, int z) { + return provider.renderLeft(x, y, z); + } + + public boolean renderRight(int x, int y, int z) { + return provider.renderRight(x, y, z); + } + + public boolean renderFront(int x, int y, int z) { + return provider.renderFront(x, y, z); + } + + public boolean renderBack(int x, int y, int z) { + return provider.renderBack(x, y, z); + } + + public WorldProvider getProvider() { + return provider; + } +} diff --git a/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java b/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java new file mode 100644 index 0000000..d362199 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java @@ -0,0 +1,47 @@ +package ru.olamedia.olacraft.world.chunk; + +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); + + public ChunkMeshBulder(String name) { + super(name); + } + + public boolean isFull() { + return chunks.remainingCapacity() == 0; + } + + public void add(Chunk chunk) { + chunks.offer(chunk); + } + + public void clear() { + chunks.clear(); + } + + public void tick() throws InterruptedException { + if (!chunks.isEmpty()) { + Chunk chunk = chunks.take(); + chunk.getMesh(); + } + } + + @Override + public void run() { + // glc.makeCurrent(); + while (true) { + // main loop + try { + tick(); + // Thread.sleep(10); // or wait/join etc + } catch (InterruptedException ex) { + // cleanup here + Thread.currentThread().interrupt(); // for nested loops + break; + } + } + } +} diff --git a/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java b/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java new file mode 100644 index 0000000..e440740 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java @@ -0,0 +1,114 @@ +package ru.olamedia.olacraft.world.chunk; + +import java.util.HashMap; + +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class ChunkSlice { + private WorldProvider provider; + private int leftX; + private int bottomY; + private int backZ; + private int width; + private int height; + private int depth; + + public ChunkSlice(WorldProvider provider, int width, int height, int depth) { + this.provider = provider; + this.width = width; + this.height = height; + this.depth = depth; + } + + protected HashMap<String, Chunk> chunks = new HashMap<String, Chunk>(); + + public Chunk getChunk(int x, int y, int z) { + String key = x + ";" + y + ";" + z; + if (chunks.containsKey(key)) { + return chunks.get(key); + } else { + Chunk chunk = new Chunk(provider); + chunk.setLocation(x * 16, y * 16, z * 16); + chunks.put(key, chunk); + return chunk; + } + } + + /** + * @return the width + */ + public int getWidth() { + return width; + } + + /** + * @param width + * the width to set + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * @return the height + */ + public int getHeight() { + return height; + } + + /** + * @param height + * the height to set + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * @return the depth + */ + public int getDepth() { + return depth; + } + + /** + * @param depth + * the depth to set + */ + public void setDepth(int depth) { + this.depth = depth; + } + + public void setLocation(int x, int y, int z) { + leftX = x; + bottomY = y; + backZ = z; + } + + public void setCenter(int x, int y, int z) { + leftX = x - width / 2; + bottomY = y - height / 2; + backZ = z - depth / 2; + } + + /** + * @return the leftX + */ + public int getX() { + return leftX; + } + + /** + * @return the bottomY + */ + public int getY() { + return bottomY; + } + + /** + * @return the backZ + */ + public int getZ() { + return backZ; + } +} diff --git a/src/ru/olamedia/olacraft/world/chunk/package-info.java b/src/ru/olamedia/olacraft/world/chunk/package-info.java new file mode 100644 index 0000000..314ea35 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.chunk;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/data/ChunkData.java b/src/ru/olamedia/olacraft/world/data/ChunkData.java new file mode 100644 index 0000000..a1abc9e --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/ChunkData.java @@ -0,0 +1,86 @@ +package ru.olamedia.olacraft.world.data; + +import java.io.Serializable; +import java.util.BitSet; + +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; + +public class ChunkData implements Serializable { + private static final long serialVersionUID = -5704237444737895501L; + public ChunkLocation location; + public static transient int SIZE = 4096; + // private boolean[] notEmpty = new boolean[SIZE]; + private BitSet emptyBlocks = new BitSet(4096); + public int notEmptyCount = 0; + + // public transient int[] type = new int[SIZE]; + // /public transient ChunkLightData light; + + public ChunkData() { + // light = new ChunkLightData(); + } + + public void compact() { + if (notEmptyCount == 0) { + emptyBlocks = null; + } + } + + public static int normalize(int v) { + int n = v; + if (n > 15) { + n = n % 16; + } + if (n < 0) { + n = 16 + n % 16 - 1; + // v = 15 - v; + } + // System.out.println("normalize(" + v + ") = " + n); + return n; + } + + public static int getId(int xInsideChunk, int yInsideChunk, int zInsideChunk) { + xInsideChunk = normalize(xInsideChunk); + yInsideChunk = normalize(yInsideChunk); + zInsideChunk = normalize(zInsideChunk); + int id = xInsideChunk * 16 * 16 + yInsideChunk * 16 + zInsideChunk; + if (id > SIZE) { + System.err.println("Exception while getID(" + xInsideChunk + "," + yInsideChunk + "," + zInsideChunk + ")"); + throw new ArrayIndexOutOfBoundsException(id); + } + return id; + } + + public boolean isEmpty(BlockLocation blockLocation) { + if (notEmptyCount == 0) { + return true; + } + int id = getId(Chunk.in(blockLocation.x), Chunk.in(blockLocation.y), Chunk.in(blockLocation.z)); + return isEmpty(id); + // return !notEmpty[id]; + } + + public boolean isEmpty(int id) { + if (notEmptyCount == 0) { + return true; + } + return emptyBlocks.get(id); + } + + public void setEmpty(int id, boolean isEmpty) { + if (isEmpty(id) != isEmpty) { + if (!isEmpty) { + notEmptyCount++; + } else { + notEmptyCount--; + } + } + emptyBlocks.set(id, isEmpty); + } + + public boolean isEmpty() { + return notEmptyCount == 0; + } +} diff --git a/src/ru/olamedia/olacraft/world/data/ChunkLightData.java b/src/ru/olamedia/olacraft/world/data/ChunkLightData.java new file mode 100644 index 0000000..f574420 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/ChunkLightData.java @@ -0,0 +1,102 @@ +package ru.olamedia.olacraft.world.data; + +import ru.olamedia.olacraft.world.dataProvider.AbstractChunkDataProvider; + +/** + * The daylight calculated as sum of sunlight + emitted light + * The nightlight calculated as sum of emitted light + * + * The light at some time of a day calculated as part of daylight + part of + * nightlight (ex 30% of night + 70% of daylight) - sum of two array's elements + */ +public class ChunkLightData { + public static int SIZE = 4096; + /** + * Constant sunlight level + */ + public byte[] sunLevel = new byte[SIZE]; + /** + * Constant sunlight level + */ + public byte[] emittedLevel = new byte[SIZE]; + /** + * Constant light level during middle of a day + */ + public byte[] daytimeLevel = new byte[SIZE]; + /** + * Constant light level during midnight + */ + public byte[] nighttimeLevel = new byte[SIZE]; + public boolean isCalculated = false; + public boolean isSunlevelCalculated = false; + public byte[] level = new byte[SIZE]; + + public static int normalize(int v) { + int n = v; + if (n > 15) { + n = n % 16; + } + if (n < 0) { + n = 16 + n % 16 - 1; + // v = 15 - v; + } + // System.out.println("normalize(" + v + ") = " + n); + return n; + } + + public static int getId(int xInsideChunk, int yInsideChunk, int zInsideChunk) { + xInsideChunk = normalize(xInsideChunk); + yInsideChunk = normalize(yInsideChunk); + zInsideChunk = normalize(zInsideChunk); + int id = xInsideChunk * 16 * 16 + yInsideChunk * 16 + zInsideChunk; + if (id > SIZE) { + System.err.println("Exception while getID(" + xInsideChunk + "," + yInsideChunk + "," + zInsideChunk + ")"); + throw new ArrayIndexOutOfBoundsException(id); + } + return id; + } + + private static byte sunlight = 15; + + public void fillSunlight() { + // simplify: straight from top to bottom, utility to fill top layer + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + sunLevel[getId(x, 15, z)] = sunlight; + } + } + } + + public void copySunlightFromAbove(ChunkLightData above) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + sunLevel[getId(x, 15, z)] = above.sunLevel[getId(x, 0, z)]; + } + } + System.out.print("Copy sunlight"); + } + + /** + * Sunlight falling down until meets nonempty block from data + * + * @param data + */ + public void falldownSunlight(ChunkData data) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = 14; y >= 0; y--) { + if (!data.isEmpty(getId(x, y, z))) { + break; + } else { + sunLevel[getId(x, y, z)] = sunLevel[getId(x, y + 1, z)]; + } + } + } + } + } + + public void receiveNeighborLight(AbstractChunkDataProvider abstractChunkDataProvider) { + + } + +} diff --git a/src/ru/olamedia/olacraft/world/data/HeightMap.java b/src/ru/olamedia/olacraft/world/data/HeightMap.java new file mode 100644 index 0000000..b2c0a63 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/HeightMap.java @@ -0,0 +1,42 @@ +package ru.olamedia.olacraft.world.data; + +import java.io.Serializable; + +/** + * Heightmap + * Useful when looking for spawn location, calculating light + * + * @author olamedia + * + */ +public class HeightMap implements Serializable { + private static final long serialVersionUID = -6777972159522169977L; + public byte[][] map; // -128..127 + public HeightMap(){ + + } + public HeightMap(int width, int height) { + map = new byte[width][height]; + } + + public void setHeight(int x, int y, int height) { + map[x][y] = (byte) height; + } + + public int getHeight(int x, int y) { + return map[x][y]; + } + + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + for (int x = 0; x < map.length; x++){ + for (int z = 0; z < map[x].length; z++){ + b.append(map[x][z]); + b.append(","); + } + b.append("\n"); + } + return b.toString(); + } +} diff --git a/src/ru/olamedia/olacraft/world/data/RegionData.java b/src/ru/olamedia/olacraft/world/data/RegionData.java new file mode 100644 index 0000000..fa292d2 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/RegionData.java @@ -0,0 +1,57 @@ +package ru.olamedia.olacraft.world.data; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; + +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.RegionLocation; +import ru.olamedia.olacraft.world.location.SectorLocation; + +/** + * Region is a 16x16 range of sectors. (256x256x256 blocks) + * + * @author olamedia + * + */ +public class RegionData implements Serializable { + private static final long serialVersionUID = 7449677895073874520L; + public RegionLocation location; + public HeightMap heightMap = new HeightMap(256, 256); + public SectorData[][] sectorData = new SectorData[16][16]; + + public void writeTo(OutputStream stream) throws IOException { + ObjectOutputStream out = new ObjectOutputStream(stream); + out.writeObject(this); + out.close(); + } + + public static RegionData loadFrom(InputStream stream) throws IOException, ClassNotFoundException { + ObjectInputStream in = new ObjectInputStream(stream); + RegionData data = (RegionData) in.readObject(); + in.close(); + return data; + } + + public static RegionData createEmpty(RegionLocation location) { + RegionData data = new RegionData(); + data.location = location; + return data; + } + + public ChunkData getChunkData(ChunkLocation chunkLocation) { + SectorData sector = getSectorData(chunkLocation.getSectorLocation()); + int y = Chunk.in(chunkLocation.y + 128); // minHeight = -128 + return sector.chunkData[y]; + } + + public SectorData getSectorData(SectorLocation sectorLocation) { + int x = Chunk.in(sectorLocation.x); + int z = Chunk.in(sectorLocation.z); + return sectorData[x][z]; + } +} diff --git a/src/ru/olamedia/olacraft/world/data/SectorData.java b/src/ru/olamedia/olacraft/world/data/SectorData.java new file mode 100644 index 0000000..12a97cd --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/SectorData.java @@ -0,0 +1,33 @@ +package ru.olamedia.olacraft.world.data; + +import java.io.Serializable; + +import ru.olamedia.olacraft.world.location.SectorLocation; + +/** + * Sector: set of all chunks by one x,z vertical + * + * @author olamedia + * + */ +public class SectorData implements Serializable{ + private static final long serialVersionUID = 5304471397211814748L; + public HeightMap heightMap; // locations of highest nonempty blocks + public ChunkData[] chunkData; // 256/16 = 16 + public SectorLocation location; + + public static int yIndex(int y) { + return (y + 128) / 16; + // 1: (-128 + 128) / 16 = 0 + // ...... + // 15: (-114 + 128) / 16 = 14/16 = 0 + // 16: (-113 + 128) / 16 = 15/16 = 0 + // 17: (-112 + 128) / 16 = 16/16 = 1 + } + public static SectorData generate(){ + SectorData data = new SectorData(); + data.heightMap = new HeightMap(16, 16); + data.chunkData = new ChunkData[16]; + return data; + } +} diff --git a/src/ru/olamedia/olacraft/world/data/UnavailableDataException.java b/src/ru/olamedia/olacraft/world/data/UnavailableDataException.java new file mode 100644 index 0000000..a75a42e --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/UnavailableDataException.java @@ -0,0 +1,23 @@ +package ru.olamedia.olacraft.world.data; + +public class UnavailableDataException extends Exception { + + public UnavailableDataException() { + super(); + } + + public UnavailableDataException(String message, Throwable cause) { + super(message, cause); + } + + public UnavailableDataException(String message) { + super(message); + } + + public UnavailableDataException(Throwable cause) { + super(cause); + } + + private static final long serialVersionUID = -8955947061088863309L; + +} diff --git a/src/ru/olamedia/olacraft/world/data/package-info.java b/src/ru/olamedia/olacraft/world/data/package-info.java new file mode 100644 index 0000000..2a171a6 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.data;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java new file mode 100644 index 0000000..1670ef3 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java @@ -0,0 +1,60 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.data.SectorData; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.RegionLocation; +import ru.olamedia.olacraft.world.location.SectorLocation; + +abstract public class AbstractChunkDataProvider { + /** + * is data already available or we should wait + * + * @param RegionLocation + * @return + */ + public boolean isChunkAvailable(ChunkLocation chunkLocation) { + return this.isRegionAvailable(chunkLocation.getRegionLocation()); + } + + public boolean isSectorAvailable(SectorLocation sectorLocation) { + return this.isRegionAvailable(sectorLocation.getRegionLocation()); + } + + abstract public boolean isRegionAvailable(RegionLocation regionLocation); + + /** + * we need this chunk now, send request to server or preload + * + * @param RegionLocation + */ + public void loadChunk(ChunkLocation chunkLocation) { + //System.out.println("loadChunk(" + chunkLocation + ")"); + this.loadRegion(chunkLocation.getRegionLocation()); + //System.out.println("loadChunk(" + chunkLocation + ")--"); + } + + public void loadSector(SectorLocation sectorLocation) { + this.loadRegion(sectorLocation.getRegionLocation()); + } + + abstract public void loadRegion(RegionLocation regionLocation); + + /** + * Get data if already available + * + * @param RegionLocation + * @return + */ + public ChunkData getChunk(ChunkLocation chunkLocation) { + return this.getRegion(chunkLocation.getRegionLocation()).getChunkData(chunkLocation); + } + + public SectorData getSector(SectorLocation sectorLocation) { + return this.getRegion(sectorLocation.getRegionLocation()).getSectorData(sectorLocation); + } + + abstract public RegionData getRegion(RegionLocation regionLocation); + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java new file mode 100644 index 0000000..23270a7 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java @@ -0,0 +1,70 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import ru.olamedia.olacraft.world.data.RegionData; +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 List<String> loading = new ArrayList<String>(); + + public CachedChunkDataProvider(AbstractChunkDataProvider provider) { + this.provider = provider; + } + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[CachedChunkDataProvider] " + s); + } + } + + @Override + public boolean isRegionAvailable(RegionLocation regionLocation) { + String key = regionLocation.toString();// regionLocation.x + "-" + + // regionLocation.z; + if (regionMap.containsKey(key)) { + return true; + } + if (loading.contains(key)) { + // return false; + } + return provider.isRegionAvailable(regionLocation); + } + + @Override + public void loadRegion(RegionLocation regionLocation) { + String key = regionLocation.toString(); + //debug("loadRegion(" + regionLocation + ")"); + if (!regionMap.containsKey(key)) { + if (!loading.contains(key)) { + debug("load()"); + loading.add(key); + provider.loadRegion(regionLocation); + }else{ + //debug("loadRegion(" + regionLocation + ") already in loading"); + } + }else{ + debug("error: loadRegion(" + regionLocation + ") already in regionMap"); + } + } + + @Override + public RegionData getRegion(RegionLocation regionLocation) { + String key = regionLocation.toString(); + if (regionMap.containsKey(key)) { + return regionMap.get(key); + } else { + RegionData data = provider.getRegion(regionLocation); + regionMap.put(key, data); + loading.remove(key); + return data; + } + } + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java new file mode 100644 index 0000000..514081f --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java @@ -0,0 +1,218 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.generator.HeightMapGenerator; +import ru.olamedia.olacraft.world.generator.RegionGenerator; +import ru.olamedia.olacraft.world.location.RegionLocation; + +public class LocalChunkDataProvider extends AbstractChunkDataProvider { + private String worldName; + private String path; + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[LocalChunkDataProvider] " + s); + } + } + + public LocalChunkDataProvider(String worldName) { + this.worldName = worldName; + path = "data" + File.separator + this.worldName; + File worldDir = new File(path); + if (!worldDir.isDirectory()) { + worldDir.mkdirs(); + } + } + + private int[] seed; + + private int[] getSeed() throws IOException { + if (null == seed) { + String filename = path + File.separator + "world.seed"; + File seedFile = new File(filename); + // md5 - 32x0-f = 16 bytes or 8 short int + seed = new int[8]; + if (seedFile.exists()) { + InputStream in = null; + DataInputStream din = null; + in = new FileInputStream(seedFile); + din = new DataInputStream(in); + for (int i = 0; i < 8; i++) { + seed[i] = din.readShort(); + } + din.close(); + in.close(); + } else { + OutputStream out = new FileOutputStream(seedFile); + DataOutputStream dout = new DataOutputStream(out); + for (int i = 0; i < 8; i++) { + seed[i] = (int) (Integer.MAX_VALUE * Math.random()); + dout.writeShort(seed[i]); + } + dout.close(); + out.close(); + } + } + return seed; + } + + @Override + public boolean isRegionAvailable(RegionLocation regionLocation) { + return true; + } + + @Override + public void loadRegion(RegionLocation regionLocation) { + // do nothing... + debug("loadRegion(" + regionLocation + ")"); + } + + private ChunkData createChunk(int chunkX, int chunkY, int chunkZ) { + debug("createChunk " + chunkX + " " + chunkY + " " + chunkZ); + ChunkData data = new ChunkData(); + try { + getSeed(); + } catch (IOException e) { + e.printStackTrace(); + } + HeightMapGenerator.minValue = 1; + HeightMapGenerator.maxValue = 64; + HeightMapGenerator.init(); + HeightMapGenerator.seed = seed[0]; + int[][] heightMap = HeightMapGenerator.getChunkHeightMap(chunkX, chunkZ); + for (int y = 0; y < 16; y++) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + data.setEmpty(ChunkData.getId(x, y, z), (heightMap[x][z] < chunkY * 16 + y)); + } + } + } + return data; + } + + @Override + public RegionData getRegion(RegionLocation regionLocation) { + String filename = path + File.separator + regionLocation.getFilename(); + RegionData data = null; + // TODO READ/WRITE FILE + File chunkFile = new File(filename); + if (chunkFile.exists()) { + InputStream in; + try { + in = new FileInputStream(chunkFile); + data = RegionData.loadFrom(in); + in.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } else { + data = generateRegion(regionLocation); + try { + chunkFile.createNewFile(); + FileOutputStream out = new FileOutputStream(chunkFile); + data.writeTo(out); + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return data; + } + + public RegionData generateRegion(RegionLocation regionLocation) { + RegionData data = new RegionData(); + data.location = regionLocation; + // TODO FILL HERE + RegionGenerator generator = new RegionGenerator(); + try { + generator.setSeed(getSeed()); + } catch (IOException e) { + e.printStackTrace(); + } + generator.generate(data); + return data; + } + + public ChunkData get(int chunkX, int chunkY, int chunkZ) { + debug("get " + chunkX + " " + chunkY + " " + chunkZ); + ChunkData data = null; + String filename = path + File.separator + chunkX + "_" + chunkY + "_" + chunkZ + ".chunk"; + /* + * File chunkFile = new File(filename); + * if (chunkFile.exists()) { + * try { + * InputStream in = new FileInputStream(chunkFile); + * DataInputStream din = new DataInputStream(in); + * data = new ChunkData(); + * data.readFrom(din); + * din.close(); + * in.close(); + * } catch (FileNotFoundException e) { + * e.printStackTrace(); + * } catch (IOException e) { + * e.printStackTrace(); + * } + * } else { + */ + data = createChunk(chunkX, chunkY, chunkZ); + /* + * OutputStream out = null; + * ByteArrayOutputStream bout = null; + * DataOutputStream dout = null; + * try { + * chunkFile.createNewFile(); + * out = new FileOutputStream(chunkFile); + * // bout = new ByteArrayOutputStream(4096); + * dout = new DataOutputStream(out); + * data.writeTo(dout); + * // dout.flush(); + * // out.write(bout.toByteArray()); + * out.flush(); + * } catch (IOException e) { + * e.printStackTrace(); + * } finally { + * if (null != dout) { + * try { + * dout.close(); + * } catch (IOException e) { + * e.printStackTrace(); + * } + * } + * if (null != bout) { + * try { + * bout.close(); + * } catch (IOException e) { + * e.printStackTrace(); + * } + * } + * if (null != out) { + * try { + * out.close(); + * } catch (IOException e) { + * e.printStackTrace(); + * } + * } + * } + * } + */ + return data; + } + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/LocalRegionDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/LocalRegionDataProvider.java new file mode 100644 index 0000000..447bcc3 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/LocalRegionDataProvider.java @@ -0,0 +1,57 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class LocalRegionDataProvider { + private String worldName; + private String path; + + public LocalRegionDataProvider(String worldName) { + this.worldName = worldName; + path = "data" + File.separator + this.worldName; + File worldDir = new File(path); + if (!worldDir.isDirectory()) { + worldDir.mkdirs(); + } + } + + private int[] seed; + + private int[] getSeed() throws IOException { + if (null == seed) { + String filename = path + File.separator + "world.seed"; + File seedFile = new File(filename); + // md5 - 32x0-f = 16 bytes or 8 short int + seed = new int[8]; + if (seedFile.exists()) { + InputStream in = null; + DataInputStream din = null; + in = new FileInputStream(seedFile); + din = new DataInputStream(in); + for (int i = 0; i < 8; i++) { + seed[i] = din.readShort(); + } + din.close(); + in.close(); + } else { + OutputStream out = new FileOutputStream(seedFile); + DataOutputStream dout = new DataOutputStream(out); + for (int i = 0; i < 8; i++) { + seed[i] = (int) (Integer.MAX_VALUE * Math.random()); + dout.writeShort(seed[i]); + } + dout.close(); + out.close(); + } + } + return seed; + } + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java new file mode 100644 index 0000000..8284ff9 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java @@ -0,0 +1,75 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.esotericsoftware.kryonet.Connection; + +import ru.olamedia.olacraft.network.GameClient; +import ru.olamedia.olacraft.network.packet.GetRegionPacket; +import ru.olamedia.olacraft.network.packet.IPacket; +import ru.olamedia.olacraft.network.packet.IPacketListener; +import ru.olamedia.olacraft.network.packet.RegionDataPacket; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.location.RegionLocation; + +public class RemoteChunkDataProvider extends AbstractChunkDataProvider implements IPacketListener { + + private GameClient client; + private HashMap<String, RegionData> map = new HashMap<String, RegionData>(); + private List<String> loading = new ArrayList<String>(); + + public RemoteChunkDataProvider(GameClient client) { + this.client = client; + this.client.addPacketListener(this); + } + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[RemoteChunkDataProvider] " + s); + } + } + + @Override + public void loadRegion(RegionLocation regionLocation) { + String key = regionLocation.toString(); + debug("loadRegion(" + key + ")"); + if (!loading.contains(key)) { + loading.add(key); + client.send(new GetRegionPacket(regionLocation)); + debug("sent packet: GetRegionPacket"); + } + } + + @Override + public boolean isRegionAvailable(RegionLocation regionLocation) { + String key = regionLocation.toString(); + if (loading.contains(key)) { + return false; + } + return map.containsKey(key); + } + + @Override + public RegionData getRegion(RegionLocation regionLocation) { + String key = regionLocation.toString(); + RegionData data = map.get(key); + map.remove(key); + return data; + } + + @Override + public void onPacket(Connection connection, IPacket p) { + if (p instanceof RegionDataPacket) { + debug("received packet [conn " + connection.getID() + "]: ChunkDataPacket"); + RegionData data = ((RegionDataPacket) p).data; + String key = data.location.toString(); + map.put(key, data); + loading.remove(key); + } + } + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/package-info.java b/src/ru/olamedia/olacraft/world/dataProvider/package-info.java new file mode 100644 index 0000000..6a411e6 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.dataProvider;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java b/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java new file mode 100644 index 0000000..c3e32b5 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java @@ -0,0 +1,157 @@ +package ru.olamedia.olacraft.world.generator; + +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.data.HeightMap; +import ru.olamedia.olacraft.world.location.RegionLocation; +import libnoiseforjava.NoiseGen.NoiseQuality; +import libnoiseforjava.exception.ExceptionInvalidParam; +import libnoiseforjava.module.Billow; +import libnoiseforjava.module.Blend; +import libnoiseforjava.module.Max; +import libnoiseforjava.module.Perlin; +import libnoiseforjava.module.RidgedMulti; +import libnoiseforjava.module.ScaleBias; +import libnoiseforjava.module.Select; +import libnoiseforjava.module.Turbulence; +import libnoiseforjava.util.NoiseMap; +import libnoiseforjava.util.NoiseMapBuilderPlane; + +public class HeightMapGenerator { + public static int minValue; + public static int maxValue; + + public static int seed = (int) (Integer.MAX_VALUE * Math.random()); + + private static Billow plainsNoise; + private static ScaleBias plains; + private static RidgedMulti hillsNoise; + private static ScaleBias hills; + private static RidgedMulti mountainsNoise; + private static ScaleBias mountains; + private static Perlin terrainType; + private static Blend blendedTerrain; + private static Select selectedTerrain; + private static Max maxTerrain; + private static Turbulence turbulence; + private static ScaleBias finalTerrain; + + private static boolean isInitialized = false; + + public static void init() { + if (isInitialized) { + return; + } + isInitialized = true; + try { + // PLAINS + plainsNoise = new Billow(); + plainsNoise.setFrequency(0.01); + plains = new ScaleBias(plainsNoise); + plains.setScale(0.05); + plains.setBias(-0.75); + // HILLS + hillsNoise = new RidgedMulti(); + hillsNoise.setFrequency(0.01); + hills = new ScaleBias(hillsNoise); + hills.setScale(0.5); + hills.setBias(-0.75); + // MOUNTAINS + mountainsNoise = new RidgedMulti(); + mountainsNoise.setFrequency(0.04); + mountainsNoise.setOctaveCount(6); + turbulence = new Turbulence(mountainsNoise); + turbulence.setFrequency(0.2); + turbulence.setPower(1); + mountains = new ScaleBias(turbulence); + mountains.setScale(1.0); + mountains.setBias(-1.25); + terrainType = new Perlin(); + terrainType.setOctaveCount(6); + terrainType.setFrequency(0.06); + terrainType.setPersistence(0.25); + terrainType.setNoiseQuality(NoiseQuality.QUALITY_BEST); + selectedTerrain = new Select(plains, mountains, terrainType); + selectedTerrain.setBounds(0, 1); + selectedTerrain.setEdgeFalloff(0.125); + blendedTerrain = new Blend(plains, mountains, terrainType); + maxTerrain = new Max(plains, turbulence); + finalTerrain = new ScaleBias(maxTerrain); + finalTerrain.setBias(2); + setSeed(seed); + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + } + + public static void setSeed(int newseed) { + seed = newseed; + plainsNoise.setSeed(seed); + hillsNoise.setSeed(seed); + mountainsNoise.setSeed(seed); + terrainType.setSeed(seed); + } + + public static int[][] getChunkHeightMap(int chunkX, int chunkZ) { + init(); + try { + NoiseMapBuilderPlane builder = new NoiseMapBuilderPlane(16, 16); + // builder.enableSeamless(true); + // Perlin plains = new Perlin(); + + // Select finalTerrain = new Select(plains, mountains, null); + // finalTerrain.setControlModule(terrainType); + // finalTerrain.setBounds(0.0, 1000); + // finalTerrain.setEdgeFalloff(1.25); + + NoiseMap heightMap = new NoiseMap(16, 16); + builder.setSourceModule(maxTerrain); + builder.setDestNoiseMap(heightMap); + double bx = chunkX; + double bz = chunkZ; + builder.setDestSize(16, 16); + builder.setBounds(bx, bx + 1, bz, bz + 1); + builder.build(); + double[][] heights = heightMap.getNoiseMap(); + int[][] ints = new int[16][16]; + // System.out.print("heightmap:"); + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + // System.out.print(((float) heights[x][z]) + ";"); + ints[x][z] = (int) (minValue + (maxValue - minValue) * (heights[x][z] + 1) / 2); + } + } + // System.out.println(""); + return ints; + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + return null; + } + + public static HeightMap getHeightMap(RegionLocation location) { + init(); + HeightMap map = new HeightMap(256, 256); + try { + NoiseMapBuilderPlane builder = new NoiseMapBuilderPlane(256, 256); + NoiseMap heightMap = new NoiseMap(256, 256); + builder.setSourceModule(finalTerrain); + builder.setDestNoiseMap(heightMap); + builder.setDestSize(256, 256); + float bx = location.x; + float bz = location.z; + builder.setBounds(bx, bx + 1, bz, bz + 1); + builder.build(); + double[][] heights = heightMap.getNoiseMap(); + for (int x = 0; x < 256; x++) { + for (int z = 0; z < 256; z++) { + map.setHeight(x, z, 0); + //(int) (minValue + (maxValue - minValue) * (heights[x][z] + 1) / 2) + } + } + return map; + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/ImprovedNoise.java b/src/ru/olamedia/olacraft/world/generator/ImprovedNoise.java new file mode 100644 index 0000000..365aa12 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/ImprovedNoise.java @@ -0,0 +1,61 @@ +package ru.olamedia.olacraft.world.generator; + +//JAVA REFERENCE IMPLEMENTATION OF IMPROVED NOISE - COPYRIGHT 2002 KEN PERLIN. + +public final class ImprovedNoise { + static public double noise(double x, double y, double z) { + int X = (int) Math.floor(x) & 255, // FIND UNIT CUBE THAT + Y = (int) Math.floor(y) & 255, // CONTAINS POINT. + Z = (int) Math.floor(z) & 255; + x -= Math.floor(x); // FIND RELATIVE X,Y,Z + y -= Math.floor(y); // OF POINT IN CUBE. + z -= Math.floor(z); + double u = fade(x), // COMPUTE FADE CURVES + v = fade(y), // FOR EACH OF X,Y,Z. + w = fade(z); + int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES + // OF + B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE + // CORNERS, + + return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), // AND ADD + grad(p[BA], x - 1, y, z)), // BLENDED + lerp(u, grad(p[AB], x, y - 1, z), // RESULTS + grad(p[BB], x - 1, y - 1, z))),// FROM 8 + lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), // CORNERS + grad(p[BA + 1], x - 1, y, z - 1)), // OF CUBE + lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1)))); + } + + static double fade(double t) { + return t * t * t * (t * (t * 6 - 15) + 10); + } + + static double lerp(double t, double a, double b) { + return a + t * (b - a); + } + + static double grad(int hash, double x, double y, double z) { + int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE + double u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS. + v = h < 4 ? y : h == 12 || h == 14 ? x : z; + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); + } + + static final int p[] = new int[512], permutation[] = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, + 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, + 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, + 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, + 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, + 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, + 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, + 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, + 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, + 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, + 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, + 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 }; + static { + for (int i = 0; i < 256; i++) + p[256 + i] = p[i] = permutation[i]; + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/Lerp.java b/src/ru/olamedia/olacraft/world/generator/Lerp.java new file mode 100644 index 0000000..cc009fe --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/Lerp.java @@ -0,0 +1,27 @@ +package ru.olamedia.olacraft.world.generator; + +public class Lerp { + public static float lerp(float x, float x1, float x2, float q00, float q01) { + return ((x2 - x) / (x2 - x1)) * q00 + ((x - x1) / (x2 - x1)) * q01; + } + + public static float biLerp(float x, float y, float q11, float q12, float q21, float q22, float x1, float x2, + float y1, float y2) { + float r1 = lerp(x, x1, x2, q11, q21); + float r2 = lerp(x, x1, x2, q12, q22); + + return lerp(y, y1, y2, r1, r2); + } + + public static float triLerp(float x, float y, float z, float q000, float q001, float q010, float q011, float q100, + float q101, float q110, float q111, float x1, float x2, float y1, float y2, float z1, float z2) { + float x00 = lerp(x, x1, x2, q000, q100); + float x10 = lerp(x, x1, x2, q010, q110); + float x01 = lerp(x, x1, x2, q001, q101); + float x11 = lerp(x, x1, x2, q011, q111); + float r0 = lerp(y, y1, y2, x00, x01); + float r1 = lerp(y, y1, y2, x10, x11); + + return lerp(z, z1, z2, r0, r1); + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java b/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java new file mode 100644 index 0000000..9657e32 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java @@ -0,0 +1,71 @@ +package ru.olamedia.olacraft.world.generator; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.HeightMap; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.data.SectorData; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.SectorLocation; + +public class RegionGenerator { + private int[] seed; + + public void setSeed(int[] seed) { + this.seed = seed; + } + + public void debug(String s) { + System.out.println("[RegionGenerator] " + s); + } + + public void generate(RegionData data) { + HeightMapGenerator.minValue = -5; + HeightMapGenerator.maxValue = 100; + HeightMapGenerator.init(); + HeightMapGenerator.seed = seed[0]; + BlockLocation offset = data.location.getBlockLocation(); + // int[][] heightMap = + // HeightMapGenerator.getHeightMap(data.location.getBlockLocation().x, + // data.location.getBlockLocation().z, 256, 256); + debug(data.location.toString()); + data.heightMap = HeightMapGenerator.getHeightMap(data.location); + //debug(data.heightMap.toString()); + data.sectorData = new SectorData[16][16]; + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + // CREATE SECTOR + SectorData sector = new SectorData(); + sector.location = new SectorLocation(offset.x + x * 16, offset.z + z * 16); + sector.heightMap = new HeightMap(16, 16); + sector.chunkData = new ChunkData[16]; + for (int y = 0; y < 16; y++) { + // CREATE CHUNK + ChunkData chunk = new ChunkData(); + chunk.location = new ChunkLocation(sector.location.x, y, sector.location.z); + int chunkOffsetY = y * 16 - 128; + for (int inChunkX = 0; inChunkX < 16; inChunkX++) { + for (int inChunkZ = 0; inChunkZ < 16; inChunkZ++) { + int height = data.heightMap.getHeight(x * 16 + inChunkX, z * 16 + inChunkZ); + //System.out.println("height: " + height); + sector.heightMap.setHeight(inChunkX, inChunkZ, height); + for (int inChunkY = 0; inChunkY < 16; inChunkY++) { + //height = sector.heightMap.getHeight(inChunkX, inChunkZ); + int id = ChunkData.getId(inChunkX, inChunkY, inChunkZ); + if (chunkOffsetY + inChunkY > height) { + chunk.setEmpty(id, true); + } else { + //System.out.println("not empty, height: " + height); + chunk.setEmpty(id, false); + } + } + } + } + chunk.compact(); + sector.chunkData[y] = chunk; + } + data.sectorData[x][z] = sector; + } + } + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/package-info.java b/src/ru/olamedia/olacraft/world/generator/package-info.java new file mode 100644 index 0000000..2f62117 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.generator;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/location/BlockLocation.java b/src/ru/olamedia/olacraft/world/location/BlockLocation.java new file mode 100644 index 0000000..b104bad --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/BlockLocation.java @@ -0,0 +1,37 @@ +package ru.olamedia.olacraft.world.location; + +import java.io.Serializable; + +import ru.olamedia.olacraft.world.chunk.Chunk; + +public class BlockLocation implements Serializable { + private static final long serialVersionUID = -4987461467575474762L; + public int x; + public int y; + public int z; + + public BlockLocation() { + } + + public BlockLocation(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public ChunkLocation getChunkLocation() { + return new ChunkLocation(Chunk.v(x), Chunk.v(y + 128), Chunk.v(z)); + } + + public RegionLocation getRegionLocation() { + return new RegionLocation(Chunk.v(Chunk.v(x)), Chunk.v(Chunk.v(z))); + } + + public SectorLocation getSectorLocation() { + return new SectorLocation(Chunk.v(x), Chunk.v(z)); + } + + public String toString() { + return "blockLocation[" + x + "," + y + "," + z + "]"; + } +} diff --git a/src/ru/olamedia/olacraft/world/location/ChunkLocation.java b/src/ru/olamedia/olacraft/world/location/ChunkLocation.java new file mode 100644 index 0000000..57acc52 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/ChunkLocation.java @@ -0,0 +1,40 @@ +package ru.olamedia.olacraft.world.location; + +import java.io.Serializable; + +import ru.olamedia.olacraft.world.chunk.Chunk; + +public class ChunkLocation implements Serializable { + private static final long serialVersionUID = -3620722885522274470L; + + public ChunkLocation() { + + } + + public ChunkLocation(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int x; + public int y; + public int z; + + public SectorLocation getSectorLocation() { + return new SectorLocation(x, z); + } + + public RegionLocation getRegionLocation() { + return new RegionLocation(Chunk.v(x), Chunk.v(z)); + } + + public String toString() { + return "chunkLocation[" + x + "," + y + "," + z + "]"; + } + /* + * public BlockSlice getSlice(){ + * + * } + */ +} diff --git a/src/ru/olamedia/olacraft/world/location/RegionLocation.java b/src/ru/olamedia/olacraft/world/location/RegionLocation.java new file mode 100644 index 0000000..59a57ec --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/RegionLocation.java @@ -0,0 +1,29 @@ +package ru.olamedia.olacraft.world.location; + +import java.io.Serializable; + +public class RegionLocation implements Serializable { + private static final long serialVersionUID = -141619138379029773L; + public int x; + public int z; + + public RegionLocation() { + } + + public RegionLocation(int x, int z) { + this.x = x; + this.z = z; + } + + public String toString() { + return "regionLocation[" + x + "," + z + "]"; + } + + public String getFilename() { + return "" + x + "_" + z + ".region"; + } + + public BlockLocation getBlockLocation() { + return new BlockLocation(x * 256, 0, z * 256); + } +} diff --git a/src/ru/olamedia/olacraft/world/location/SectorLocation.java b/src/ru/olamedia/olacraft/world/location/SectorLocation.java new file mode 100644 index 0000000..59390b8 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/SectorLocation.java @@ -0,0 +1,29 @@ +package ru.olamedia.olacraft.world.location; + +import java.io.Serializable; + +import ru.olamedia.olacraft.world.chunk.Chunk; + +public class SectorLocation implements Serializable { + private static final long serialVersionUID = 4500216114186249375L; + + public SectorLocation() { + + } + + public SectorLocation(int x, int z) { + this.x = x; + this.z = z; + } + + public int x; + public int z; + + public RegionLocation getRegionLocation() { + return new RegionLocation(Chunk.v(x), Chunk.v(z)); + } + + public String toString() { + return "sectorLocation[" + x + "," + z + "]"; + } +} diff --git a/src/ru/olamedia/olacraft/world/location/package-info.java b/src/ru/olamedia/olacraft/world/location/package-info.java new file mode 100644 index 0000000..37f205d --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.location;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/package-info.java b/src/ru/olamedia/olacraft/world/package-info.java new file mode 100644 index 0000000..914d8d2 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/provider/IChunkProvider.java b/src/ru/olamedia/olacraft/world/provider/IChunkProvider.java new file mode 100644 index 0000000..5076c75 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/IChunkProvider.java @@ -0,0 +1,8 @@ +package ru.olamedia.olacraft.world.provider; + +import ru.olamedia.olacraft.world.block.Block; + +public interface IChunkProvider { + public boolean isEmptyBlock(int x, int y, int z); + public Block getBlock(int x, int y, int z); +} diff --git a/src/ru/olamedia/olacraft/world/provider/WorldProvider.java b/src/ru/olamedia/olacraft/world/provider/WorldProvider.java new file mode 100644 index 0000000..8dacce9 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/WorldProvider.java @@ -0,0 +1,130 @@ +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.data.ChunkData; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.dataProvider.AbstractChunkDataProvider; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.RegionLocation; + +public class WorldProvider { + private WorldInfo info = new WorldInfo(); + private AbstractChunkDataProvider dataProvider; + + public WorldInfo getInfo() { + return info; + } + + public void setInfo(WorldInfo worldInfo) { + info = worldInfo; + } + + /* + * public AbstractChunkDataProvider getChunkDataProvider() { + * return dataProvider; + * } + */ + + public void setChunkDataProvider(AbstractChunkDataProvider provider) { + dataProvider = provider; + } + + public SpawnLocation getSpawnLocation(int connectionId) { + SpawnLocation l = new SpawnLocation(); + int maxShift = 10; + l.x = (int) (maxShift - Math.random() * 2 * maxShift); + l.z = (int) (maxShift - Math.random() * 2 * maxShift); + System.out.print("Searching spawn Y"); + BlockLocation spawnLocation = new BlockLocation(l.x, 0, l.z); + for (int y = info.maxHeight; y > info.minHeight; y--) { + // search for floor block + spawnLocation.y = y; + System.out.print(y + ". "); + ChunkData chunk = dataProvider.getChunk(spawnLocation.getChunkLocation()); + boolean notEmpty = !chunk.isEmpty(ChunkData.getId(Chunk.in(spawnLocation.x), Chunk.in(spawnLocation.y), + Chunk.in(spawnLocation.z))); + if (notEmpty) { + // found + l.y = y + 1; + System.out.println("found: " + y); + return l; + } + } + System.out.println("not found "); + // not found + l.y = info.maxHeight; + return l; + } + + public boolean renderBottom(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y - 1, z)); + } + + public boolean renderTop(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y + 1, z)); + } + + public boolean renderLeft(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x - 1, y, z)); + } + + public boolean renderRight(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x + 1, y, z)); + } + + public boolean renderBack(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y, z - 1)); + } + + public boolean renderFront(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y, z + 1)); + } + + public boolean isEmptyBlock(int x, int y, int z) { + BlockLocation blockLocation = new BlockLocation(x, y, z); + + if (isChunkAvailable(blockLocation.getChunkLocation())) { + ChunkData data = dataProvider.getChunk(blockLocation.getChunkLocation()); + if (null != data) { + return data.isEmpty(blockLocation); + } + } + return false; + } + + public void requestChunk(int chunkX, int chunkY, int chunkZ) { + ChunkLocation chunkLocation = new ChunkLocation(chunkX, chunkY, chunkZ); + // getChunkDataProvider().loadRegion(chunkLocation.getRegionLocation()); + loadChunk(chunkLocation); + } + + public boolean isChunkAvailable(ChunkLocation chunkLocation) { + return dataProvider.isChunkAvailable(chunkLocation); + } + + public boolean isAvailableBlock(int x, int y, int z) { + BlockLocation blockLocation = new BlockLocation(x, y, z); + return dataProvider.isChunkAvailable(blockLocation.getChunkLocation()); + } + + public void loadChunk(ChunkLocation chunkLocation) { + dataProvider.loadChunk(chunkLocation); + } + + public RegionData getRegion(RegionLocation regionLocation) { + return dataProvider.getRegion(regionLocation); + } + + 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); + } +} diff --git a/src/ru/olamedia/olacraft/world/provider/blockData/BlockData.java b/src/ru/olamedia/olacraft/world/provider/blockData/BlockData.java new file mode 100644 index 0000000..94be4d7 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/blockData/BlockData.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.world.provider.blockData; + +public class BlockData { + +} diff --git a/src/ru/olamedia/olacraft/world/provider/blockData/EmptyBlockData.java b/src/ru/olamedia/olacraft/world/provider/blockData/EmptyBlockData.java new file mode 100644 index 0000000..ab17107 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/blockData/EmptyBlockData.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.world.provider.blockData; + +public class EmptyBlockData implements IBlockData{ + public boolean notEmpty = false; +} diff --git a/src/ru/olamedia/olacraft/world/provider/blockData/IBlockData.java b/src/ru/olamedia/olacraft/world/provider/blockData/IBlockData.java new file mode 100644 index 0000000..95dfb35 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/blockData/IBlockData.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.world.provider.blockData; + +public interface IBlockData { + public boolean notEmpty = false; +} diff --git a/src/ru/olamedia/olacraft/world/provider/blockData/package-info.java b/src/ru/olamedia/olacraft/world/provider/blockData/package-info.java new file mode 100644 index 0000000..0fa952a --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/blockData/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.provider.blockData;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/provider/package-info.java b/src/ru/olamedia/olacraft/world/provider/package-info.java new file mode 100644 index 0000000..c43643a --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.provider;
\ No newline at end of file |