package projectzombie.world.chunk; import java.nio.FloatBuffer; import java.util.ArrayList; import java.util.Random; import bdf.classes.IBdfClassManager; import bdf.types.BdfArray; import bdf.types.BdfNamedList; import bdf.types.BdfObject; import gl_engine.MathHelpers; import gl_engine.matrix.Matrix4; import gl_engine.range.Range2i; import gl_engine.texture.TextureRef3D; import gl_engine.vec.Vec2d; import gl_engine.vec.Vec2i; import gl_engine.vec.Vec3d; import projectzombie.Main; import projectzombie.display.Camera; import projectzombie.entity.Entity; import projectzombie.entity.EntityAlive; import projectzombie.entity.EntityHoldsEntities; import projectzombie.entity.EntityKillWithParticles; import projectzombie.entity.EntityParticle; import projectzombie.entity.EntityParticlePart; import projectzombie.entity.particle.ParticleBreak; import projectzombie.entity.tileentity.TileEntity; import projectzombie.init.Tiles; import projectzombie.model.IModel; import projectzombie.model.Model; import projectzombie.model.ModelChunk; import projectzombie.tiles.Tile; import projectzombie.util.math.TileState; import projectzombie.util.math.random.RandomHelpers; import projectzombie.world.layer.Layer; public class Chunk implements IBdfClassManager { public static final Range2i CHUNK_SIZE = new Range2i(16, 16); public static final Chunk CHUNK_EMPTY = new ChunkEmpty(); public static final int CHUNK_INDEX = CHUNK_SIZE.mx * CHUNK_SIZE.my; public static final Random rand = new Random(); public static int SIMULATION_DISTANCE = 10; public static int RENDER_DISTANCE = 2; public static boolean SHOW_CHUNKS = false; private Tile tiles_back[] = new Tile[CHUNK_INDEX]; private Tile tiles_front[] = new Tile[CHUNK_INDEX]; private byte tiles_front_meta[] = new byte[CHUNK_INDEX]; private byte tiles_back_meta[] = new byte[CHUNK_INDEX]; private byte tiles_lighting[] = new byte[CHUNK_INDEX]; public ArrayList entities = new ArrayList(); private Layer layer; public Vec2i c_pos; private boolean dirty; private boolean light_dirty; private boolean render_dirty; private ModelChunk model; public boolean isDirty() { if(entities.size() > 0) { return true; } return dirty; } public void clearDirty() { dirty = false; } private void setDirty() { this.light_dirty = true; this.render_dirty = true; this.dirty = true; } public boolean isLightDirty() { return light_dirty; } public void resetLightDirty() { this.light_dirty = false; } @Override public void BdfClassLoad(BdfObject bdf) { BdfNamedList nl = bdf.getNamedList(); // Load all the tiles and meta short[] tb = nl.get("tilesBack").getShortArray(); short[] tf = nl.get("tilesFront").getShortArray(); byte[] mb = nl.get("metaBack").getByteArray(); byte[] mf = nl.get("metaFront").getByteArray(); for(int i=0;i 1.125 || Math.abs(pos.y) > 1.125 || Math.abs(pos.z) > 1.125) { continue; } float px = (float)(p.pos.x - 0.5f - Camera.camera.x); float py = (float)(p.pos.y); float pz = (float)(p.pos.z - 0.5f - Camera.camera.y); float k = Model.OFFSET; float tsx = p.tex.sx+k; float tex = p.tex.ex-k; float tsy = p.tex.sy+k; float tey = p.tex.ey-k; float tz = p.tex.z; float g = (float)p.getFade(); float s = (float)p.size / 2; float f = p.flags; float a_si = p.animationSize; float a_sp = p.animationSpeed; float a = -s, b = s, c = 0, d = 0; if(p.isFlat()) { c = a; d = b; a = 0; b = 0; } /* layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aTex; layout (location = 2) in vec2 aTexY; layout (location = 3) in vec3 aOffset; layout (location = 4) in vec2 aAnimate; layout (location = 5) in vec3 aFlags; */ float[] verticies = { -s, a, c, tex, tsy, tz, tsy, tey, px, py, pz, a_si, a_sp, g, 0, f, -s, b, d, tex, tey, tz, tsy, tey, px, py, pz, a_si, a_sp, g, 0, f, +s, b, d, tsx, tey, tz, tsy, tey, px, py, pz, a_si, a_sp, g, 0, f, +s, a, c, tsx, tsy, tz, tsy, tey, px, py, pz, a_si, a_sp, g, 0, f, }; for(int j=0;j cx + CHUNK_SIZE.mx || px < cx || py > cy + CHUNK_SIZE.my || py < cy) { // Process the entity by layer and remove the entity from the array layer.spawnEntity(e); entities.remove(i); i -= 1; } } } public void createTileEntity(Vec2i pos, TileEntity te) { TileEntity te_old = getTileEntity(pos); // Kill the old tile entity if it exists if(te_old != null) { te_old.kill(); } te.setPos(new Vec3d(pos.x, 0, pos.y)); spawnEntity(te); } public void destroyTileEntity(Vec2i pos) { TileEntity te = getTileEntity(pos); if(te != null) { te.kill(); } } public TileEntity getTileEntity(Vec2i pos) { for(Entity e : entities) { if(e instanceof TileEntity && e.getPos().xz().toInt().equal(pos)) { return (TileEntity)e; } } return null; } public void setBackTile(TileState tile, Vec2i pos) { // Get the id Vec2i cpos = new Vec2i(0, 0); cpos.x = MathHelpers.mod(pos.x, CHUNK_SIZE.mx); cpos.y = MathHelpers.mod(pos.y, CHUNK_SIZE.my); int id = cpos.getId(CHUNK_SIZE); setBackTile(tile, id); } public void setBackTile(TileState tile, int id) { Vec2i pos = Vec2i.fromId(CHUNK_SIZE, id).add(c_pos.multiply(16)); tiles_back[id].onDestroy(layer, this, new TileState(tiles_back[id], tiles_back_meta[id]), tile, pos); // Set the back tile tiles_back[id] = tile.tile; tiles_back_meta[id] = tile.meta; setDirty(); tile.tile.onGenerate(layer, this, tile, pos); } public void setFrontTile(TileState tile, Vec2i pos) { // Get the id Vec2i cpos = new Vec2i(0, 0); cpos.x = MathHelpers.mod(pos.x, CHUNK_SIZE.mx); cpos.y = MathHelpers.mod(pos.y, CHUNK_SIZE.my); int id = cpos.getId(CHUNK_SIZE); setFrontTile(tile, id); } public void setFrontTile(TileState tile, int id) { Vec2i pos = Vec2i.fromId(CHUNK_SIZE, id).add(c_pos.multiply(16)); tiles_front[id].onDestroy(layer, this, new TileState(tiles_front[id], tiles_front_meta[id]), tile, pos); // Set the front tile this.tiles_front[id] = tile.tile; this.tiles_front_meta[id] = tile.meta; setDirty(); tile.tile.onGenerate(layer, this, tile, pos); } public TileState getBackTile(Vec2i pos) { // Get the id Vec2i cpos = new Vec2i(0, 0); cpos.x = MathHelpers.mod(pos.x, CHUNK_SIZE.mx); cpos.y = MathHelpers.mod(pos.y, CHUNK_SIZE.my); int id = cpos.getId(CHUNK_SIZE); return getBackTile(id); } public TileState getBackTile(int id) { // Send back the back tile TileState ts = new TileState(this.tiles_back[id], this.tiles_back_meta[id]); ts.light = getLightLevel(id); return ts; } public TileState getFrontTile(Vec2i pos) { // Get the id Vec2i cpos = new Vec2i(0, 0); cpos.x = MathHelpers.mod(pos.x, CHUNK_SIZE.mx); cpos.y = MathHelpers.mod(pos.y, CHUNK_SIZE.my); int id = cpos.getId(CHUNK_SIZE); return getFrontTile(id); } public TileState getFrontTile(int id) { // Send back the front tile TileState ts = new TileState(this.tiles_front[id], this.tiles_front_meta[id]); ts.light = getLightLevel(id); return ts; } public void breakBackTile(Vec2i pos) { TileState ts = getBackTile(pos); setDirty(); if(!ts.tile.unbreakable) { setBackTile(layer.layergen.getTileDestroyed(layer, pos), pos); spawnEntity(new ParticleBreak(new Vec3d(pos.x + 0.5, 0, pos.y + 0.5), new Vec3d(0, 0, 0), ts.tile.getModel(ts.meta))); } } public void breakFrontTile(Vec2i pos) { TileState ts = getFrontTile(pos); setDirty(); if(!ts.tile.unbreakable) { setFrontTile(Tiles.VOID.getDefaultState(), pos); spawnEntity(new ParticleBreak(new Vec3d(pos.x + 0.5, 0, pos.y + 0.5), new Vec3d(0, 0, 0), ts.tile.getModel(ts.meta))); } } public double getLightLevel(int id) { return tiles_lighting[id] / (double)Byte.MAX_VALUE; } public double getLightLevel(Vec2i pos) { // Get the id Vec2i cpos = new Vec2i(0, 0); cpos.x = MathHelpers.mod(pos.x, CHUNK_SIZE.mx); cpos.y = MathHelpers.mod(pos.y, CHUNK_SIZE.my); int id = cpos.getId(CHUNK_SIZE); return getLightLevel(id); } public void setLightLevel(double light, int id) { this.tiles_lighting[id] = (byte)(light * Byte.MAX_VALUE); } public void setLightLevel(double light, Vec2i pos) { // Get the id Vec2i cpos = new Vec2i(0, 0); cpos.x = MathHelpers.mod(pos.x, CHUNK_SIZE.mx); cpos.y = MathHelpers.mod(pos.y, CHUNK_SIZE.my); int id = cpos.getId(CHUNK_SIZE); setLightLevel(light, id); } public void killEntity(Entity e) { if(e instanceof EntityKillWithParticles) { ((EntityKillWithParticles)e).killWithParticles(); } entities.remove(e); } public ArrayList getNearbyEntities(Vec2d pos, double distance) { // Get the list of entities to send back ArrayList nearby_entities = new ArrayList(); // Loop over the entities for(Entity e : entities) { Vec2d epos = e.getPos().xz(); if( epos.x + distance > pos.x && epos.x - distance < pos.x && epos.y + distance > pos.y && epos.y - distance < pos.y ) { if(pos.squareDistance(epos) < distance) { nearby_entities.add(e); } } } // Send back the entities return nearby_entities; } public void tickRandomly() { // Get a random tile int id = RandomHelpers.randrange(rand, CHUNK_INDEX); Vec2i pos = Vec2i.fromId(CHUNK_SIZE, id); pos.x += c_pos.x * 16; pos.y += c_pos.y * 16; // Randomly select the front and back tiles TileState ts; if(rand.nextBoolean()) { ts = getBackTile(id); } else { ts = getFrontTile(id); } // Tick the tile ts.tile.tickRandomly(layer, this, ts, pos); } public void free() { if(this.model != null) { this.model.free(); this.model = null; } } }