package game;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;
import org.lwjgl.opengl.GL11;
public class ChunkManager {
private HashMap<String, Chunk> chunkMap = new HashMap<String, Chunk>();
private HashMap<String, Chunk> sleepingChunks = new HashMap<String, Chunk>();
private int seed;
private static int chunkNum = 5;
public ChunkManager() {
Random rand = new Random();
rand.setSeed(System.nanoTime());
seed = rand.nextInt() & 0xFFFF;
}
public void generate(Vector3f pos) {
int inChunkX, inChunkZ;
inChunkX = pos.x < 0 ? (int) (pos.x - Game.CHUNK_SIZE) / Game.CHUNK_SIZE : (int) pos.x / Game.CHUNK_SIZE;
inChunkZ = pos.z < 0 ? (int) (pos.z - Game.CHUNK_SIZE) / Game.CHUNK_SIZE : (int) pos.z / Game.CHUNK_SIZE;
for (int x = inChunkX - chunkNum; x <= inChunkX + chunkNum - 1; x++) {
for (int z = inChunkZ - chunkNum; z <= inChunkZ + chunkNum - 1; z++) {
getChunk(x, z);
}
}
}
public void updateVisibleChunks(Vector3f pos) {
// we want to check if a chunk is near the player.
int inChunkX, inChunkZ;
inChunkX = pos.x < 0 ? (int) (pos.x - Game.CHUNK_SIZE) / Game.CHUNK_SIZE : (int) pos.x / Game.CHUNK_SIZE;
inChunkZ = pos.z < 0 ? (int) (pos.z - Game.CHUNK_SIZE) / Game.CHUNK_SIZE : (int) pos.z / Game.CHUNK_SIZE;
// if the chunk exists but is too far from the player, add it to the list of deletions.
ArrayList<String> deletions = new ArrayList<String>();
for (Iterator<String> chunkIds = chunkMap.keySet().iterator(); chunkIds
.hasNext();) {
String chunkId = chunkIds.next();
String[] coords = chunkId.split(",");
if ((Math.abs(inChunkX - Integer.parseInt(coords[0])) > chunkNum)
|| (Math.abs(inChunkZ - Integer.parseInt(coords[1])) > chunkNum)) {
deletions.add(chunkId);
}
}
// All "deleted" chunks are shipped off to sleepingChunks, where they don't render,
// and they can get brought back in later.
for (Iterator<String> toDelete = deletions.iterator(); toDelete
.hasNext();) {
String deletion = toDelete.next();
sleepingChunks.put(deletion, chunkMap.get(deletion));
chunkMap.remove(deletion);
}
// This loads chunks around the player if they don't exist already.
// It starts in the chunk the player's in, and proceeds outward until it hits
// the radius given in chunkNum
String hashKey = String.valueOf(inChunkX) + "," + String.valueOf(inChunkZ);
for (int radius = 0; radius < chunkNum; radius++) {
for (int x = inChunkX - radius; x <= inChunkX + radius; x++) {
for (int z = inChunkZ - radius; z <= inChunkZ + radius; z++) {
hashKey = String.valueOf(x) + "," + String.valueOf(z);
if (!chunkMap.containsKey(hashKey)
&& (Game.ups % 5 == 0)) // lol throttling, actually a TODO eventing
{
getChunk(x, z);
return;
}
}
}
}
}
public void getChunk(int offsetX, int offsetZ) {
String hashKey = String.valueOf(offsetX) + "," + String.valueOf(offsetZ);
if (sleepingChunks.containsKey(hashKey))
{
chunkMap.put(hashKey, sleepingChunks.get(hashKey));
sleepingChunks.remove(hashKey);
}
else
{
generateChunk(offsetX, offsetZ);
}
}
public void generateChunk(int offsetX, int offsetZ) {
// Create the terrain
String hashKey = String.valueOf(offsetX) + ","
+ String.valueOf(offsetZ);
chunkMap.put(hashKey, new Chunk(offsetX, offsetZ, new Vector3(
Game.CHUNK_SIZE, Game.CHUNK_HEIGHT, Game.CHUNK_SIZE),
new Vector3f(1.0f, 1.0f, 1.0f), new Vector3f((float) offsetX
* Game.CHUNK_SIZE, 0.0f, (float) offsetZ
* Game.CHUNK_SIZE)));
final int TERRAIN_MAX_HEIGHT = 32;
final int TERRAIN_MIN_HEIGHT = 12;
final int TERRAIN_GEN_SEED = seed;
final float TERRAIN_GEN_NOISE_SIZE = 0.01f;
final float TERRAIN_GEN_PERSISTENCE = 0.9f;
final int TERRAIN_GEN_OCTAVES = 6;
chunkMap.get(hashKey).generateTerrain(TERRAIN_MAX_HEIGHT,
TERRAIN_MIN_HEIGHT, TERRAIN_GEN_SEED,
TERRAIN_GEN_NOISE_SIZE, TERRAIN_GEN_PERSISTENCE,
TERRAIN_GEN_OCTAVES, Game.TEXTURES);
}
public void render() {
// Save the current matrix
GL11.glPushMatrix();
// Add the translation matrix
GL11.glTranslatef(0.0f, 0.0f, 0.0f);
for (Iterator<String> chunkIds = chunkMap.keySet().iterator(); chunkIds
.hasNext();) {
String chunkId = chunkIds.next();
chunkMap.get(chunkId).render();
}
// Restore the matrix
GL11.glPopMatrix();
}
public void release() {
for (Iterator<String> chunkIds = chunkMap.keySet().iterator(); chunkIds
.hasNext();) {
String chunkId = chunkIds.next();
chunkMap.get(chunkId).release();
}
}
/* Returns true if there is a solid cube at the given coordinates. */
public boolean solidAt(Vector3f coordinates) {
int xIndex, zIndex;
xIndex = (int) Math.floor(coordinates.x / Game.CHUNK_SIZE);
zIndex = (int) Math.floor(coordinates.z / Game.CHUNK_SIZE);
String hashKey = String.valueOf(xIndex) + "," + String.valueOf(zIndex);
if (chunkMap.containsKey(hashKey)) {
return chunkMap.get(hashKey).solidAt(coordinates);
}
return false;
}
public void deleteBlockAt(Vector3f pos) {
// TODO Auto-generated method stub
int inChunkX, inChunkZ;
inChunkX = pos.x < 0 ? (int) (pos.x - Game.CHUNK_SIZE) / Game.CHUNK_SIZE : (int) pos.x / Game.CHUNK_SIZE;
inChunkZ = pos.z < 0 ? (int) (pos.z - Game.CHUNK_SIZE) / Game.CHUNK_SIZE : (int) pos.z / Game.CHUNK_SIZE;
String hashKey = String.valueOf(inChunkX) + "," + String.valueOf(inChunkZ);
if (chunkMap.containsKey(hashKey)) // lol throttling, actually a TODO
{
chunkMap.get(hashKey).deleteBlockAt(pos);
return;
}
}
public void placeBlockAt(Vector3f coordinates, Vector3f target) {
// find block intersection
Vector3f midpoint;
for (int i = 0; i < 10; i++) { // ten passes of precision;
midpoint = Vector3f.midpoint(coordinates, target);
if (solidAt(midpoint))
{
//still solid, back it up
target = midpoint;
} else {
coordinates = midpoint;
}
}
int inChunkX = coordinates.x < 0 ? (int) (coordinates.x - Game.CHUNK_SIZE) / Game.CHUNK_SIZE : (int) coordinates.x / Game.CHUNK_SIZE;
int inChunkZ = coordinates.z < 0 ? (int) (coordinates.z - Game.CHUNK_SIZE) / Game.CHUNK_SIZE : (int) coordinates.z / Game.CHUNK_SIZE;
String hashKey = String.valueOf(inChunkX) + "," + String.valueOf(inChunkZ);
if (chunkMap.containsKey(hashKey)) // lol throttling, actually a TODO
{
chunkMap.get(hashKey).createBlockAt(coordinates);
return;
}
}
public int getCubeTypeAtVector(Vector3f pos) {
// TODO Auto-generated method stub
int inChunkX, inChunkZ;
inChunkX = pos.x < 0 ? (int) (pos.x - Game.CHUNK_SIZE) / Game.CHUNK_SIZE : (int) pos.x / Game.CHUNK_SIZE;
inChunkZ = pos.z < 0 ? (int) (pos.z - Game.CHUNK_SIZE) / Game.CHUNK_SIZE : (int) pos.z / Game.CHUNK_SIZE;
String hashKey = String.valueOf(inChunkX) + "," + String.valueOf(inChunkZ);
if (chunkMap.containsKey(hashKey)) // lol throttling, actually a TODO
{
return chunkMap.get(hashKey).getCubeTypeAtVector(pos);
}
return 0;
}
}