Made chunk saving asynchronous, added auto saving and asynchronous

saving, seperated chunks into their own files, made chunks unload to a
file instead of to memory, fixed a lighting based performance bug.
This commit is contained in:
josua 2020-08-27 23:49:55 +10:00
parent c5e36b6f79
commit 76fce435b1
19 changed files with 458 additions and 144 deletions

View File

@ -34,6 +34,7 @@ import projectzombie.settings.Settings;
import projectzombie.time.GameTimer;
import projectzombie.time.NoSleep;
import projectzombie.worker.WorkerChunks;
import projectzombie.worker.WorkerFile;
import projectzombie.worker.WorkerLighting;
import projectzombie.world.World;
import projectzombie.world.chunk.ChunkEventHandler;
@ -48,9 +49,11 @@ public class Main
public static AudioEngine audio;
public static Random rand = new Random();
public static Menu menu;
public static WorkerFile workerFile;
public static WorkerLighting workerLighting;
public static WorkerChunks workerChunks;
public static WorkerChunks[] workerChunks;
public static boolean game_paused = false;
public static boolean running = true;
public static int tickrate = 10;
public static void main(String[] args) throws IOException
@ -59,12 +62,19 @@ public class Main
{
clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
workerChunks = new WorkerChunks();
workerLighting = new WorkerLighting();
workerFile = new WorkerFile();
workerFile.start();
workerChunks.start();
workerLighting = new WorkerLighting();
workerLighting.start();
workerChunks = new WorkerChunks[4];
for(int i=0;i<workerChunks.length;i++) {
workerChunks[i] = new WorkerChunks();
workerChunks[i].start();
}
MathHelpers.init();
Settings.init();
Environment.init(args);
@ -116,9 +126,8 @@ public class Main
finally
{
// Kill the worker thread
workerLighting.kill();
workerChunks.kill();
// Kill the worker threads
running = false;
}
}
}

View File

@ -1,6 +1,7 @@
package projectzombie.display;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.lwjgl.BufferUtils;
@ -34,9 +35,9 @@ public class DisplayLighting
private static int lighting_last_x = 0;
private static int lighting_last_y = 0;
private static boolean lighting_dirty = false;
private static boolean lighting_new = false;
public static int lightmap;
private static AtomicBoolean lighting_new = new AtomicBoolean(false);
private static AtomicReference<Lighting> lighting = new AtomicReference<DisplayLighting.Lighting>();
public static void setDirty() {
@ -49,7 +50,7 @@ public class DisplayLighting
private static void setLighting(Lighting lighting) {
DisplayLighting.lighting.set(lighting);
lighting_new = true;
lighting_new.set(true);
}
public DisplayLighting() {
@ -230,23 +231,31 @@ public class DisplayLighting
Lighting lighting = getLighting();
Layer layer = Main.world.getLayer();
if(lighting_new.getAndSet(false))
{
for(int i=0;i<lighting.p.length/3;i++)
{
int i3 = i*3;
int x = i % lighting.w;
int y = i / lighting.w;
Vec2i tpos = new Vec2i(x + lighting.x * 16, y + lighting.y * 16);
// Store light level data from the image
layer.setLightLevel(lighting.p[i3+1], tpos);
// Store temperature and humidity data
lighting.p[i3+1] = (float)layer.getTemperature(new Vec2i(x + lighting.x * 16, y + lighting.y * 16));
lighting.p[i3+2] = (float)layer.getHumidity(new Vec2i(x + lighting.x * 16, y + lighting.y * 16));
}
}
// Copy the pixels
float[] pixels = new float[lighting.p.length];
for(int i=0;i<pixels.length;i++) {
pixels[i] = lighting.p[i];
}
for(int x2=0;x2<lighting.w;x2++) {
for(int y2=0;y2<lighting.h;y2++)
{
int i = (x2 + y2 * lighting.w) * 3;
// Send temperature and humidity data to the image
pixels[i+1] = (float)layer.getTemperature(new Vec2i(x2 + lighting.x * 16, y2 + lighting.y * 16));
pixels[i+2] = (float)layer.getHumidity(new Vec2i(x2 + lighting.x * 16, y2 + lighting.y * 16));
}
}
Vec2d ppos = Main.player.getPos().xz();
calculateEntityLighting(layer, lighting, Main.player, pixels);
@ -266,22 +275,6 @@ public class DisplayLighting
}
}
if(lighting_new)
{
for(int i=0;i<lighting.p.length/3;i++)
{
int x = i % lighting.w;
int y = i / lighting.w;
Vec2i tpos = new Vec2i(x + lighting.x * 16, y + lighting.y * 16);
// Store light level data from the image
layer.setLightLevel(lighting.p[i*3+1], tpos);
}
lighting_new = false;
}
ByteBuffer pixels_b = BufferUtils.createByteBuffer(pixels.length);
for(int i=0;i<pixels.length;i++) {
@ -316,6 +309,8 @@ public class DisplayLighting
(float)(lighting.y * 16 - Camera.camera.y - 0.5));
}
}
public static void clearLighting()

View File

@ -105,6 +105,7 @@ public class EntityPlayer extends Entity implements
}
inventory.addItem(new ItemStack(Items.TORCH, 1));
inventory.addItem(new ItemStack(Items.LANTERN, 1));
}
public int getAmmo() {

View File

@ -8,6 +8,7 @@ public class MainloopEventHandler implements IMainloopEvent, IMainloopTask
{
public static final MainloopEventHandler MAINLOOP_EVENT_HANDLER = new MainloopEventHandler();
private long autosave_interval = 0;
private long max_mspf = 1;
public long mspf = max_mspf;
@ -45,7 +46,7 @@ public class MainloopEventHandler implements IMainloopEvent, IMainloopTask
@Override
public boolean MainLoopDelay(long millis) {
return millis > 1;
return millis > 10;
}
@Override
@ -58,6 +59,15 @@ public class MainloopEventHandler implements IMainloopEvent, IMainloopTask
{
// Stop the mainloop if the window should close
if(Main.window.shouldClose()) Main.mainloop.stop();
// Autosave every minute
autosave_interval += 1;
if(autosave_interval > 6000)
{
autosave_interval -= 6000;
Main.world.save();
}
}
}

View File

@ -41,6 +41,6 @@ public class MenuGamePause extends Menu
public void saveAndQuit()
{
Main.world.save();
Main.menu = new MenuMain();
Main.menu = new MenuSavingWorld();
}
}

View File

@ -0,0 +1,63 @@
package projectzombie.menu;
import gl_engine.matrix.Matrix4;
import gl_engine.vec.Vec3d;
import projectzombie.Main;
import projectzombie.init.Models;
import projectzombie.input.types.InputGUI;
import projectzombie.menu.gui.GUI;
import projectzombie.menu.gui.GUIAlignment;
import projectzombie.menu.gui.GUILabel;
import projectzombie.util.gl.GlHelpers;
import projectzombie.worker.WorkerChunks;
import projectzombie.world.chunk.ChunkEventHandler;
public class MenuSavingWorld extends Menu
{
private GUI gui;
public MenuSavingWorld()
{
doGameloop = true;
doGameRender = true;
keepMouse = false;
showIngameGUI = false;
GUILabel label = new GUILabel();
label.setText("Saving world...");
label.setAlign(GUIAlignment.CENTRE);
gui = new GUI();
input = new InputGUI(gui);
gui.add(label);
}
@Override
public void render()
{
double a = GlHelpers.getAspectRatio();
for(int x = 0; x < 16; x ++) {
for(int y = 0; y < 16; y ++)
{
Models.UI_STONE_BG.setModel(Matrix4.multiply(
Matrix4.scale(new Vec3d(1.25 * a, 1.25 * a, 1)),
Matrix4.translate(new Vec3d(-10 * a + 1.25 * a * x, -10 * a + 1.25 * a * y, 0))));
Models.UI_STONE_BG.render();
}
}
gui.render();
}
@Override
public void update()
{
super.update();
if(WorkerChunks.isDone()) {
Main.menu = new MenuMain();
}
}
}

View File

@ -1,6 +1,13 @@
package projectzombie.menu;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import bdf.file.BdfFileManager;
import bdf.types.BdfArray;
@ -22,7 +29,6 @@ public class MenuWorldDelete extends Menu
{
private MenuSaves parent;
private String name;
private String path;
private GUI gui;
@ -30,7 +36,6 @@ public class MenuWorldDelete extends Menu
public MenuWorldDelete(MenuSaves parent, String name, String path)
{
this.parent = parent;
this.name = name;
this.path = path;
keepMouse = false;
@ -85,8 +90,37 @@ public class MenuWorldDelete extends Menu
BdfNamedList nl = bdf.getNamedList();
BdfArray array = nl.get("saves").getArray();
File save_file = new File("./saves/" + path + ".bdf");
save_file.delete();
try
{
Files.walkFileTree(Paths.get("./saves/" + path), new FileVisitor<Path>()
{
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
});
}
catch(IOException e) {
e.printStackTrace();
}
for(int i=0;i<array.size();i++) {
BdfNamedList world_nl = array.get(i).getNamedList();

View File

@ -7,19 +7,7 @@ import projectzombie.world.chunk.Chunk;
import projectzombie.world.layer.Layer;
import projectzombie.world.layer.layergen.LayerGen;
class WorkerChunkTask
abstract class WorkerChunkTask
{
Chunk chunk;
LayerGen layergen;
Layer layer;
Random rand;
Vec2i pos;
public WorkerChunkTask(LayerGen layergen, Layer layer, Chunk chunk, Random rand, Vec2i pos) {
this.chunk = chunk;
this.layergen = layergen;
this.layer = layer;
this.rand = rand;
this.pos = pos;
}
}

View File

@ -0,0 +1,24 @@
package projectzombie.worker;
import java.util.Random;
import gl_engine.vec.Vec2i;
import projectzombie.world.chunk.Chunk;
import projectzombie.world.layer.Layer;
import projectzombie.world.layer.layergen.LayerGen;
class WorkerChunkTaskGenerate extends WorkerChunkTask
{
Chunk chunk;
LayerGen layergen;
Layer layer;
Random rand;
public WorkerChunkTaskGenerate(LayerGen layergen, Layer layer, Chunk chunk, Random rand, Vec2i pos) {
this.chunk = chunk;
this.layergen = layergen;
this.layer = layer;
this.rand = rand;
this.pos = pos;
}
}

View File

@ -0,0 +1,16 @@
package projectzombie.worker;
import gl_engine.vec.Vec2i;
import projectzombie.world.layer.Layer;
public class WorkerChunkTaskLoad extends WorkerChunkTask
{
String path;
Layer layer;
public WorkerChunkTaskLoad(String path, Layer layer, Vec2i pos) {
this.path = path;
this.layer = layer;
this.pos = pos;
}
}

View File

@ -0,0 +1,18 @@
package projectzombie.worker;
import gl_engine.vec.Vec2i;
import projectzombie.world.chunk.Chunk;
public class WorkerChunkTaskSave extends WorkerChunkTask
{
Chunk chunk;
String path;
int id;
public WorkerChunkTaskSave(String path, Vec2i pos, Chunk chunk, int id) {
this.path = path;
this.pos = pos;
this.chunk = chunk;
this.id = id;
}
}

View File

@ -5,31 +5,45 @@ import java.util.Vector;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import bdf.file.BdfFileManager;
import gl_engine.vec.Vec2i;
import projectzombie.Main;
import projectzombie.world.chunk.Chunk;
import projectzombie.world.layer.Layer;
import projectzombie.world.layer.layergen.LayerGen;
public class WorkerChunks extends Thread
{
private boolean running = false;
private Vector<WorkerChunkTask> chunks_in = new Vector<WorkerChunkTask>();
private AtomicReference<Vector<Chunk>> chunks_out = new AtomicReference<Vector<Chunk>>();
private static Vector<WorkerChunkTask> chunks_in = new Vector<WorkerChunkTask>();
private static AtomicReference<Vector<Chunk>> chunks_out = new AtomicReference<Vector<Chunk>>();
public void generateChunk(LayerGen layergen, Layer layer, Chunk chunk, Random rand, Vec2i pos) {
chunks_in.add(new WorkerChunkTask(layergen, layer, chunk, rand, pos));
public static void generateChunk(LayerGen layergen, Layer layer, Chunk chunk, Random rand, Vec2i pos) {
chunks_in.add(new WorkerChunkTaskGenerate(layergen, layer, chunk, rand, pos.copy()));
}
public Vector<Chunk> getChunks() {
public static void loadChunk(String path, Layer layer, Vec2i pos) {
chunks_in.add(new WorkerChunkTaskLoad(path, layer, pos.copy()));
}
public static void saveChunk(String path, Vec2i pos, Chunk chunk, int id) {
chunks_in.add(new WorkerChunkTaskSave(path, pos.copy(), chunk, id));
}
public static Vector<Chunk> getChunks() {
return chunks_out.getAndSet(new Vector<Chunk>());
}
public boolean hasChunk(Vec2i cpos)
public static boolean hasChunk(Vec2i cpos)
{
boolean has[] = {false};
chunks_in.forEach(c -> {
if(c.pos.equal(cpos)) {
chunks_in.forEach(c ->
{
if(
(c instanceof WorkerChunkTaskGenerate ||
c instanceof WorkerChunkTaskLoad) &&
c.pos.equal(cpos))
{
has[0] = true;
}
});
@ -41,31 +55,80 @@ public class WorkerChunks extends Thread
chunks_out.set(new Vector<Chunk>());
}
private synchronized WorkerChunkTask getNextIfAvailable()
{
if(chunks_in.size() == 0) {
return null;
} else {
return chunks_in.remove(0);
}
}
@Override
public void run()
{
running = true;
try
{
while(running)
while(Main.running)
{
if(chunks_in.size() == 0) {
Thread.sleep(1);
WorkerChunkTask ct = getNextIfAvailable();
if(ct == null) {
Thread.sleep(10);
continue;
}
WorkerChunkTask ct = chunks_in.remove(0);
// Generate a new chunk
if(ct instanceof WorkerChunkTaskGenerate)
{
WorkerChunkTaskGenerate ct_g = (WorkerChunkTaskGenerate)ct;
ct_g.layergen.generateChunk(ct_g.chunk, ct_g.layer, ct_g.rand, ct_g.pos);
chunks_out.get().add(ct_g.chunk);
}
Chunk chunk = ct.chunk;
LayerGen layergen = ct.layergen;
Layer layer = ct.layer;
Random rand = ct.rand;
Vec2i pos = ct.pos;
// Load an existing chunk
if(ct instanceof WorkerChunkTaskLoad)
{
WorkerChunkTaskLoad ct_l = (WorkerChunkTaskLoad)ct;
if(ct_l.path == null) {
System.out.println("ChunkLoad: Path is NULL");
continue;
}
String path = (
"./saves/" + ct_l.path + "/c_" + ct_l.layer.id +
"_" + ct_l.pos.x + "_" + ct_l.pos.y + ".bdf");
BdfFileManager reader = new BdfFileManager(path, true);
Chunk chunk = new Chunk(ct_l.layer, ct_l.pos, reader.getObject());
chunks_out.get().add(chunk);
}
layergen.generateChunk(chunk, layer, rand, pos);
chunks_out.get().add(chunk);
// Save a chunk
if(ct instanceof WorkerChunkTaskSave)
{
WorkerChunkTaskSave ct_s = (WorkerChunkTaskSave)ct;
if(ct_s.path == null) {
System.out.println("ChunkSave: Path is NULL");
continue;
}
String path = (
"./saves/" + ct_s.path + "/c_" + ct_s.id +
"_" + ct_s.pos.x + "_" + ct_s.pos.y + ".bdf");
BdfFileManager reader = new BdfFileManager(path, true);
ct_s.chunk.BdfClassSave(reader.getObject());
reader.saveDatabase();
}
}
}
@ -74,7 +137,7 @@ public class WorkerChunks extends Thread
}
}
public void kill() {
running = false;
public static boolean isDone() {
return chunks_in.size() == 0;
}
}

View File

@ -0,0 +1,63 @@
package projectzombie.worker;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Vector;
import java.util.zip.GZIPOutputStream;
import bdf.types.BdfReader;
import projectzombie.Main;
public class WorkerFile extends Thread
{
private static Vector<WorkerFileTask> tasks = new Vector<WorkerFileTask>();
public static void addTask(String path, BdfReader reader) {
tasks.add(new WorkerFileTask(path, reader));
}
private synchronized WorkerFileTask getNextIfAvailable()
{
if(tasks.size() == 0) {
return null;
} else {
return tasks.remove(0);
}
}
@Override
public void run()
{
try
{
while(Main.running)
{
WorkerFileTask task = getNextIfAvailable();
if(task == null) {
Thread.sleep(10);
continue;
}
try
{
OutputStream out = new FileOutputStream(task.path);
out = new GZIPOutputStream(out);
task.reader.serialize().writeToStream(out);
out.close();
}
catch(IOException e) {
e.printStackTrace();
}
}
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,14 @@
package projectzombie.worker;
import bdf.types.BdfReader;
class WorkerFileTask
{
String path;
BdfReader reader;
public WorkerFileTask(String path, BdfReader reader) {
this.reader = reader;
this.path = path;
}
}

View File

@ -2,6 +2,7 @@ package projectzombie.worker;
import java.util.concurrent.atomic.AtomicReference;
import projectzombie.Main;
import projectzombie.display.DisplayLighting;
import projectzombie.task.Task;
@ -15,7 +16,6 @@ public class WorkerLighting extends Thread
int y;
}
private boolean running;
private AtomicReference<LightingTask> task = new AtomicReference<WorkerLighting.LightingTask>();
public void processLighting(float[] lights, int width, int height, int x, int y)
@ -71,16 +71,13 @@ public class WorkerLighting extends Thread
@Override
public void run() {
super.run();
running = true;
public void run()
{
try
{
while(running)
while(Main.running)
{
LightingTask task = this.task.get();
LightingTask task = this.task.getAndSet(null);
if(task != null)
{
@ -101,7 +98,7 @@ public class WorkerLighting extends Thread
}
else {
Thread.sleep(1);
Thread.sleep(10);
}
}
}
@ -110,8 +107,4 @@ public class WorkerLighting extends Thread
e.printStackTrace();
}
}
public void kill() {
running = false;
}
}

View File

@ -13,6 +13,7 @@ import bdf.file.BdfFileManager;
import bdf.types.BdfArray;
import bdf.types.BdfNamedList;
import bdf.types.BdfObject;
import bdf.types.BdfReader;
import gl_engine.matrix.Matrix4;
import gl_engine.vec.Vec3d;
import projectzombie.Main;
@ -25,6 +26,7 @@ import projectzombie.init.Layers;
import projectzombie.menu.MenuLoadingWorld;
import projectzombie.model.Model;
import projectzombie.time.GameTimer;
import projectzombie.worker.WorkerFile;
import projectzombie.world.chunk.ChunkEventHandler;
import projectzombie.world.layer.Layer;
@ -38,7 +40,6 @@ public class World implements IBdfClassManager
private Layer loaded;
private ArrayList<Layer> layers = new ArrayList<Layer>();
private BdfFileManager file_manager;
private String path;
private int pool_vao, pool_vbo, pool_ibo;
@ -51,22 +52,18 @@ public class World implements IBdfClassManager
if(path != null)
{
path = "./saves/" + path + ".bdf";
File save_file = new File(path);
File save_dir = save_file.getParentFile();
path = "./saves/" + path + "/";
File save_dir = new File(path);
File file_dir = new File(path + "world.bdf");
if(!save_dir.exists()) {
save_dir.mkdirs();
}
if(save_file.exists()) {
file_manager = new BdfFileManager(path);
if(file_dir.exists()) {
BdfFileManager file_manager = new BdfFileManager(path + "world.bdf", true);
BdfClassLoad(file_manager.getObject());
}
else {
file_manager = new BdfFileManager(path);
}
}
}
@ -265,12 +262,17 @@ public class World implements IBdfClassManager
public void save()
{
if(file_manager != null)
if(path != null)
{
BdfObject bdf = file_manager.resetObject();
for(Layer layer : layers) {
layer.save();
}
BdfReader reader = new BdfReader();
BdfObject bdf = reader.getObject();
BdfClassSave(bdf);
file_manager.saveDatabase();
WorkerFile.addTask("./saves/" + path + "/world.bdf", reader);
}
}

View File

@ -54,7 +54,7 @@ public class Chunk implements IBdfClassManager
private byte tiles_temperature[] = new byte[CHUNK_INDEX];
private byte tiles_humidity[] = new byte[CHUNK_INDEX];
public ArrayList<Entity> entities = new ArrayList<Entity>();
private Layer layer;
public Layer layer;
public Vec2i c_pos;
private boolean dirty;
private boolean light_dirty;

View File

@ -7,6 +7,7 @@ import mainloop.task.IMainloopTask;
import projectzombie.Main;
import projectzombie.display.DisplayLighting;
import projectzombie.util.math.map.Map2DElement;
import projectzombie.worker.WorkerChunks;
import projectzombie.world.layer.Layer;
public class ChunkEventHandler implements IMainloopTask
@ -73,7 +74,7 @@ public class ChunkEventHandler implements IMainloopTask
Vec2i c_pos = new Vec2i(cx, cy);
// Is this chunk not loaded
if(!layer.chunkLoaded(c_pos) && !Main.workerChunks.hasChunk(c_pos))
if(!layer.chunkLoaded(c_pos) && !WorkerChunks.hasChunk(c_pos))
{
// Load the chunk
layer.loadChunk(c_pos);

View File

@ -21,14 +21,15 @@ import projectzombie.util.math.TileState;
import projectzombie.util.math.map.Map2D;
import projectzombie.util.math.map.Map2DElement;
import projectzombie.util.math.random.NoiseGenerator;
import projectzombie.worker.WorkerChunks;
import projectzombie.world.chunk.Chunk;
import projectzombie.world.layer.layergen.LayerGen;
public class Layer implements IBdfClassManager
{
public Map2D<Chunk> chunks;
private Map2D<Chunk> dirty_chunks;
public NoiseGenerator[] noise_gens;
public ArrayList<Vec2i> chunks_saved;
public LayerGen layergen;
private Random rand;
public long lseed;
@ -43,7 +44,7 @@ public class Layer implements IBdfClassManager
this.seed = rand.nextLong();
this.lseed = this.rand.nextLong();
this.chunks = new Map2D<Chunk>(layergen);
this.dirty_chunks = new Map2D<Chunk>(layergen);
this.chunks_saved = new ArrayList<Vec2i>();
this.layergen.init(this);
}
@ -268,19 +269,34 @@ public class Layer implements IBdfClassManager
public void loadChunks()
{
for(Chunk chunk : Main.workerChunks.getChunks())
WorkerChunks.getChunks().forEach(chunk ->
{
if(chunk.layer != this) {
return;
}
Vec2i pos = chunk.c_pos;
chunks.set(pos, chunk);
chunk.clearDirty();
});
}
private boolean hasSavedChunk(Vec2i check)
{
for(Vec2i pos : chunks_saved) {
if(pos.equal(check)) {
return true;
}
}
return false;
}
public void loadChunk(Vec2i pos)
{
// Has the chunk been saved for later
if(dirty_chunks.contains(pos)) {
chunks.set(pos, dirty_chunks.get(pos));
if(hasSavedChunk(pos)) {
WorkerChunks.loadChunk(Main.world.getSavePath(), this, pos);
}
else
@ -290,7 +306,7 @@ public class Layer implements IBdfClassManager
// Create and generate the chunk
Chunk chunk = new Chunk(this, pos, rand);
Main.workerChunks.generateChunk(layergen, this, chunk, new Random(cseed), pos);
WorkerChunks.generateChunk(layergen, this, chunk, new Random(cseed), pos);
}
}
@ -298,8 +314,13 @@ public class Layer implements IBdfClassManager
{
// Store the chunk if its a dirty chunk
Chunk chunk = chunks.get(pos);
if(chunk.isDirty()) {
dirty_chunks.set(pos, chunk);
if(chunk.isDirty())
{
WorkerChunks.saveChunk(Main.world.getSavePath(), pos, chunk, id);
if(!hasSavedChunk(pos)) {
chunks_saved.add(pos);
}
}
// Remove the chunk
@ -341,21 +362,19 @@ public class Layer implements IBdfClassManager
{
BdfNamedList nl = bdf.getNamedList();
this.layergen = LayerGenerators.loadFromID(nl.get("lgen").getInteger());
this.dirty_chunks = new Map2D<Chunk>(layergen);
BdfArray bdf_chunks = nl.get("chunks").getArray();
this.layergen = LayerGenerators.loadFromID((int)nl.get("lgen").getAutoInt());
this.chunks_saved = new ArrayList<Vec2i>(bdf_chunks.size());
this.chunks = new Map2D<Chunk>(layergen);
this.seed = nl.get("seed").getLong();
this.lseed = nl.get("lseed").getLong();
this.id = nl.get("id").getInteger();
this.id = (int)nl.get("id").getAutoInt();
this.rand = new Random();
BdfArray bdf_chunks = nl.get("chunks").getArray();
for(BdfObject bdf_chunk : bdf_chunks) {
BdfNamedList chunk_nl = bdf_chunk.getNamedList();
Vec2i cpos = new Vec2i(chunk_nl.get("pos"));
Chunk chunk = new Chunk(this, cpos, chunk_nl.get("chunk"));
dirty_chunks.set(cpos, chunk);
Vec2i c = new Vec2i(bdf_chunk);
chunks_saved.add(c);
}
layergen.init(this);
@ -368,28 +387,29 @@ public class Layer implements IBdfClassManager
nl.set("lseed", bdf.newObject().setLong(lseed));
nl.set("seed", bdf.newObject().setLong(seed));
nl.set("id", bdf.newObject().setInteger(id));
nl.set("lgen", bdf.newObject().setInteger(LayerGenerators.getLGID(this.layergen)));
nl.set("id", bdf.newObject().setAutoInt(id));
nl.set("lgen", bdf.newObject().setAutoInt(LayerGenerators.getLGID(this.layergen)));
BdfArray bdf_chunks = nl.get("chunks").getArray();
BdfArray bdf_chunks = bdf.newArray(chunks_saved.size());
nl.set("chunks", bdf.newObject().setArray(bdf_chunks));
for(Map2DElement<Chunk> chunk : dirty_chunks) {
BdfNamedList chunk_nl = bdf.newNamedList();
chunk.pos.BdfClassSave(chunk_nl.get("pos"));
chunk.o.BdfClassSave(chunk_nl.get("chunk"));
bdf_chunks.add(bdf.newObject().setNamedList(chunk_nl));
for(int i=0;i<chunks_saved.size();i++) {
chunks_saved.get(i).BdfClassSave(bdf_chunks.get(i));
}
for(Map2DElement<Chunk> chunk : chunks) {
if(dirty_chunks.contains(chunk.pos))
continue;
if(!chunk.o.isDirty())
continue;
BdfNamedList chunk_nl = bdf.newNamedList();
chunk.pos.BdfClassSave(chunk_nl.get("pos"));
chunk.o.BdfClassSave(chunk_nl.get("chunk"));
bdf_chunks.add(bdf.newObject().setNamedList(chunk_nl));
}
public void save()
{
for(Map2DElement<Chunk> chunk : chunks)
{
if(chunk.o.isDirty())
{
WorkerChunks.saveChunk(Main.world.getSavePath(), chunk.pos, chunk.o, id);
if(!hasSavedChunk(chunk.pos)) {
chunks_saved.add(chunk.pos);
}
}
}
}