blob: 4c939af86cca504080976e3eec243416e2f8b282 [file] [log] [blame] [raw]
package net.glowstone;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.logging.Level;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.BlockPopulator;
import net.glowstone.io.ChunkIoService;
/**
* A class which manages the {@link GlowChunk}s currently loaded in memory.
* @author Graham Edgecombe
*/
public final class ChunkManager {
/**
* The chunk I/O service used to read chunks from the disk and write them to
* the disk.
*/
private final ChunkIoService service;
/**
* The chunk generator used to generate new chunks.
*/
private final ChunkGenerator generator;
/**
* The world this ChunkManager is managing.
*/
private final GlowWorld world;
/**
* A map of chunks currently loaded in memory.
*/
private final Map<GlowChunk.Key, GlowChunk> chunks = new HashMap<GlowChunk.Key, GlowChunk>();
/**
* Creates a new chunk manager with the specified I/O service and world
* generator.
* @param service The I/O service.
* @param generator The world generator.
*/
public ChunkManager(GlowWorld world, ChunkIoService service, ChunkGenerator generator) {
this.world = world;
this.service = service;
this.generator = generator;
}
/**
* Gets the chunk at the specified X and Z coordinates, loading it from the
* disk or generating it if necessary.
* @param x The X coordinate.
* @param z The Z coordinate.
* @return The chunk.
*/
public GlowChunk getChunk(int x, int z) {
GlowChunk.Key key = new GlowChunk.Key(x, z);
GlowChunk chunk = chunks.get(key);
if (chunk == null) {
try {
chunk = service.read(world, x, z);
} catch (IOException e) {
chunk = null;
}
if (chunk == null) {
chunk = new GlowChunk(world, x, z);
byte[] data = generator.generate(world, new Random(), x, z);
chunk.setTypes(data);
chunks.put(key, chunk);
for (int x2 = x - 1; x2 <= x + 1; ++x2) {
for (int z2 = z - 1; z2 <= z + 1; ++z2) {
if (canPopulate(x2, z2)) {
GlowChunk chunk2 = getChunk(x2, z2);
chunk2.setPopulated(true);
for (BlockPopulator p : world.getPopulators()) {
p.populate(world, new Random(), chunk2);
System.out.println("pop " + world.getName() + " " + p.getClass().getName());
}
}
}
}
}
chunks.put(key, chunk);
}
return chunk;
}
/**
* Checks whether the given chunk can be populated by map features.
* @return Whether population is needed and safe.
*/
private boolean canPopulate(int x, int z) {
if (isLoaded(x, z)) {
if (getChunk(x, z).getPopulated()) return false;
} else {
return false;
}
for (int x2 = x - 1; x2 <= x + 1; ++x2) {
for (int z2 = z - 1; z2 <= z + 1; ++z2) {
if (!isLoaded(x2, z2)) {
return false;
}
}
}
return true;
}
/**
* Forces generation of the given chunk.
* @param x The X coordinate.
* @param z The Z coordinate.
* @return Whether the chunk was successfully regenerated.
*/
public boolean forceRegeneration(int x, int z) {
GlowChunk.Key key = new GlowChunk.Key(x, z);
GlowChunk chunk = new GlowChunk(world, x, z);
chunk.setTypes(generator.generate(world, new Random(), x, z));
if (chunk == null || !unloadChunk(x, z, false)) {
return false;
}
if (canPopulate(x, z)) {
chunk.setPopulated(true);
for (BlockPopulator p : world.getPopulators()) {
p.populate(world, new Random(), chunk);
}
}
chunks.put(key, chunk);
return true;
}
/**
* Checks whether the given Chunk is loaded.
* @param x The X coordinate.
* @param z The Z coordinate.
* @return Whether the chunk was loaded.
*/
public boolean isLoaded(int x, int z) {
GlowChunk.Key key = new GlowChunk.Key(x, z);
return chunks.get(key) != null;
}
/**
* Unloads a given chunk from memory.
* @param x The X coordinate.
* @param z The Z coordinate.
* @param save Whether to save the chunk if needed.
* @return Whether the chunk was unloaded successfully.
*/
public boolean unloadChunk(int x, int z, boolean save) {
GlowChunk.Key key = new GlowChunk.Key(x, z);
GlowChunk chunk = chunks.get(key);
if (chunk != null) {
if (save) {
try {
service.write(x, z, chunk);
} catch (IOException ex) {
GlowServer.logger.log(Level.SEVERE, "Error while saving chunk: {0}", ex.getMessage());
ex.printStackTrace();
return false;
}
}
chunks.remove(key);
return true;
}
return false;
}
/**
* Gets a list of loaded chunks.
* @return The currently loaded chunks.
*/
public GlowChunk[] getLoadedChunks() {
return chunks.values().toArray(new GlowChunk[]{});
}
/**
* Force-saves the given chunk.
* @param x The X coordinate.
* @param Z The Z coordinate.
*/
public boolean forceSave(int x, int z) {
GlowChunk.Key key = new GlowChunk.Key(x, z);
GlowChunk chunk = chunks.get(key);
if (chunk != null) {
try {
service.write(x, z, chunk);
} catch (IOException ex) {
GlowServer.logger.log(Level.SEVERE, "Error while saving chunk: {0}", ex.getMessage());
ex.printStackTrace();
return false;
}
}
return false;
}
/**
* Get the chunk generator.
*/
public ChunkGenerator getGenerator() {
return generator;
}
}