Started making chunks asynchronous

This commit is contained in:
jsrobson10 2020-08-26 20:07:23 +10:00
parent 0cbb9c8551
commit 877c5371a0
18 changed files with 251 additions and 54 deletions

View File

@ -33,6 +33,7 @@ import projectzombie.settings.Environment;
import projectzombie.settings.Settings;
import projectzombie.time.GameTimer;
import projectzombie.time.NoSleep;
import projectzombie.worker.WorkerChunks;
import projectzombie.worker.WorkerLighting;
import projectzombie.world.World;
import projectzombie.world.chunk.ChunkEventHandler;
@ -48,6 +49,7 @@ public class Main
public static Random rand = new Random();
public static Menu menu;
public static WorkerLighting workerLighting;
public static WorkerChunks workerChunks;
public static boolean game_paused = false;
public static int tickrate = 10;
@ -57,7 +59,10 @@ public class Main
{
clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
workerChunks = new WorkerChunks();
workerLighting = new WorkerLighting();
workerChunks.start();
workerLighting.start();
MathHelpers.init();
@ -113,6 +118,7 @@ public class Main
{
// Kill the worker thread
workerLighting.kill();
workerChunks.kill();
}
}
}

View File

@ -171,7 +171,7 @@ public class DisplayRenderUI
GL33.glDisable(GL33.GL_DEPTH_TEST);
if(Main.menu.doGameRender && Main.menu.showIngameGUI) {
if(Main.menu.doGameRender && Main.menu.showIngameGUI && ChunkEventHandler.loaded) {
renderGameGui();
}

View File

@ -2,6 +2,7 @@ package projectzombie.entity;
import mainloop.task.IMainloopTask;
import projectzombie.Main;
import projectzombie.world.chunk.ChunkEventHandler;
public class EntityEventHandler implements IMainloopTask
{
@ -21,7 +22,8 @@ public class EntityEventHandler implements IMainloopTask
public void MainLoopUpdate()
{
Main.menu.update();
if(!Main.menu.doGameloop) {
if(!Main.menu.doGameloop || !ChunkEventHandler.loaded) {
return;
}

View File

@ -134,6 +134,7 @@ public class Models
public static final ModelGui UI_WATER = new ModelGui(Resources.ATLAS.get("/gui/water.png"), new Vec2d(0.75, 0.75));
public static final ModelGui UI_ITEM_HOVER = new ModelGui(Resources.ATLAS.get("/gui/pixel_black.png")).setOpacity(0.25);
public static final ModelGui UI_TEXT_BG = new ModelGui(Resources.ATLAS.get("/gui/pixel_white.png")).setColor(0.5f, 0.5f, 0.5f);
public static final ModelGui UI_STONE_BG = new ModelGui(Resources.ATLAS.get("/tile/stone.png"));
public static final ModelItem UI_SLOT_ARMOR_HELMET = new ModelItem(Resources.ATLAS.get("/gui/slot_armor_helmet.png"));
public static final ModelItem UI_SLOT_ARMOR_CHEST = new ModelItem(Resources.ATLAS.get("/gui/slot_armor_chest.png"));

View File

@ -0,0 +1,62 @@
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.world.chunk.ChunkEventHandler;
public class MenuLoadingWorld extends Menu
{
private GUI gui;
public MenuLoadingWorld()
{
doGameloop = true;
doGameRender = true;
keepMouse = false;
showIngameGUI = false;
GUILabel label = new GUILabel();
label.setText("Loading 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(ChunkEventHandler.loaded) {
Main.menu = new MenuGame();
}
}
}

View File

@ -109,7 +109,7 @@ public class MenuSaves extends Menu
reader.saveDatabase();
Main.world = new World(saves.get(index).filename);
Main.menu = new MenuGame();
Main.menu = new MenuLoadingWorld();
}
private void deleteSave(int index)

View File

@ -158,7 +158,7 @@ public class MenuWorldNew extends Menu
reader.saveDatabase();
World.createWorld(path_new, seed);
Main.menu = new MenuGame();
Main.menu = new MenuLoadingWorld();
}
@Override

View File

@ -0,0 +1,25 @@
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 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,80 @@
package projectzombie.worker;
import java.util.Random;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import gl_engine.vec.Vec2i;
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>>();
public void generateChunk(LayerGen layergen, Layer layer, Chunk chunk, Random rand, Vec2i pos) {
chunks_in.add(new WorkerChunkTask(layergen, layer, chunk, rand, pos));
}
public Vector<Chunk> getChunks() {
return chunks_out.getAndSet(new Vector<Chunk>());
}
public boolean hasChunk(Vec2i cpos)
{
boolean has[] = {false};
chunks_in.forEach(c -> {
if(c.pos.equal(cpos)) {
has[0] = true;
}
});
return has[0];
}
public WorkerChunks() {
chunks_out.set(new Vector<Chunk>());
}
@Override
public void run()
{
running = true;
try
{
while(running)
{
if(chunks_in.size() == 0) {
Thread.sleep(1);
continue;
}
WorkerChunkTask ct = chunks_in.remove(0);
Chunk chunk = ct.chunk;
LayerGen layergen = ct.layergen;
Layer layer = ct.layer;
Random rand = ct.rand;
Vec2i pos = ct.pos;
layergen.generateChunk(chunk, layer, rand, pos);
chunks_out.get().add(chunk);
}
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
public void kill() {
running = false;
}
}

View File

@ -22,6 +22,7 @@ import projectzombie.display.bossbar.BossBars;
import projectzombie.entity.player.EntityPlayer;
import projectzombie.init.LayerGenerators;
import projectzombie.init.Layers;
import projectzombie.menu.MenuLoadingWorld;
import projectzombie.model.Model;
import projectzombie.time.GameTimer;
import projectzombie.world.chunk.ChunkEventHandler;
@ -197,6 +198,7 @@ public class World implements IBdfClassManager
public void setLayer(int id)
{
Main.menu = new MenuLoadingWorld();
ChunkEventHandler.loaded = false;
DisplayLighting.clearLighting();
DisplayLighting.setDirty();

View File

@ -51,6 +51,8 @@ public class Chunk implements IBdfClassManager
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];
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 Vec2i c_pos;
@ -174,11 +176,6 @@ public class Chunk implements IBdfClassManager
// Make all these tiles void
tiles_back[i] = Tiles.VOID;
tiles_front[i] = Tiles.VOID;
tiles_back_meta[i] = 0;
tiles_front_meta[i] = 0;
// Set the light level to 0
tiles_lighting[i] = 0;
}
}
@ -508,6 +505,36 @@ public class Chunk implements IBdfClassManager
return null;
}
public void setTemperature(double v, 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);
setTemperature(v, id);
}
public void setTemperature(double v, int id) {
tiles_temperature[id] = (byte)(v * 127);
}
public void setHumidity(double v, 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);
setHumidity(v, id);
}
public void setHumidity(double v, int id) {
tiles_humidity[id] = (byte)(v * 127);
}
public void setBackTile(TileState tile, Vec2i pos)
{
// Get the id

View File

@ -30,7 +30,8 @@ public class ChunkEventHandler implements IMainloopTask
// Get the layer
Vec3d ppos = Main.player.getPos();
Layer layer = Main.world.getLayer();
loaded = true;
int loaded_count = 0;
// Loop over all the chunks in this layer
for(Map2DElement<Chunk> ce : layer.chunks)
@ -41,20 +42,30 @@ public class ChunkEventHandler implements IMainloopTask
if(
// Is this chunk beyond the simulation distance
px > ce.pos.x + Chunk.SIMULATION_DISTANCE ||
px < ce.pos.x - Chunk.SIMULATION_DISTANCE ||
py > ce.pos.y + Chunk.SIMULATION_DISTANCE ||
py < ce.pos.y - Chunk.SIMULATION_DISTANCE
px > ce.pos.x + Chunk.SIMULATION_DISTANCE + 1 ||
px < ce.pos.x - Chunk.SIMULATION_DISTANCE - 1 ||
py > ce.pos.y + Chunk.SIMULATION_DISTANCE + 1 ||
py < ce.pos.y - Chunk.SIMULATION_DISTANCE - 1
) {
// Unload the chunk
layer.unloadChunk(ce.pos);
ce.o.free();
}
else {
loaded_count += 1;
}
}
if(loaded_count >= 4 * Chunk.SIMULATION_DISTANCE * (Chunk.SIMULATION_DISTANCE + 1) + 1) {
loaded = true;
}
layer.loadChunks();
// Loop over the simulation distance
for(int x=-Chunk.SIMULATION_DISTANCE;x<Chunk.SIMULATION_DISTANCE;x++) {
for(int y=-Chunk.SIMULATION_DISTANCE;y<Chunk.SIMULATION_DISTANCE;y++)
for(int x=-Chunk.SIMULATION_DISTANCE;x<=Chunk.SIMULATION_DISTANCE;x++) {
for(int y=-Chunk.SIMULATION_DISTANCE;y<=Chunk.SIMULATION_DISTANCE;y++)
{
// Get the chunk based on the player position
int cx = MathHelpers.floor(ppos.x / 16) + x;
@ -62,7 +73,7 @@ public class ChunkEventHandler implements IMainloopTask
Vec2i c_pos = new Vec2i(cx, cy);
// Is this chunk not loaded
if(!layer.chunkLoaded(c_pos))
if(!layer.chunkLoaded(c_pos) && !Main.workerChunks.hasChunk(c_pos))
{
// Load the chunk
layer.loadChunk(c_pos);

View File

@ -230,6 +230,16 @@ public class Layer implements IBdfClassManager
chunks.get(c_pos).spawnEntity(entity);
}
public void loadChunks()
{
for(Chunk chunk : Main.workerChunks.getChunks())
{
Vec2i pos = chunk.c_pos;
chunks.set(pos, chunk);
chunk.clearDirty();
}
}
public void loadChunk(Vec2i pos)
{
// Has the chunk been saved for later
@ -244,9 +254,7 @@ public class Layer implements IBdfClassManager
// Create and generate the chunk
Chunk chunk = new Chunk(this, pos, rand);
chunks.set(pos, chunk);
layergen.generateChunk(chunk, this, new Random(cseed), pos);
chunk.clearDirty();
Main.workerChunks.generateChunk(layergen, this, chunk, new Random(cseed), pos);
}
}

View File

@ -21,9 +21,7 @@ public abstract class LayerGen implements IMap2D<Chunk>
}
public abstract void generateChunk(Chunk chunk, Layer layer, Random rand, Vec2i pos);
public abstract double getTemperatureStatic(Layer layer, Vec2d pos);
public abstract double getTemperatureDynamic(Layer layer, Vec2d pos);
public abstract double getHumidity(Layer layer, Vec2d pos);
public abstract double getTemperature(Layer layer, Vec2d pos);
public abstract void spawnEntities(Layer layer, Random rand);
public abstract TileState getTileDestroyed(Layer layer, Vec2i pos);
public abstract ColorRange getLightLevel();

View File

@ -109,18 +109,8 @@ public class LayerGenBossArena extends LayerGen implements LayerGenRememberPlaye
}
@Override
public double getTemperatureStatic(Layer layer, Vec2d pos) {
public double getTemperature(Layer layer, Vec2d pos) {
return 0.8;
}
@Override
public double getTemperatureDynamic(Layer layer, Vec2d pos) {
return 0.8;
}
@Override
public double getHumidity(Layer layer, Vec2d pos) {
return 0;
}
}

View File

@ -22,8 +22,6 @@ import projectzombie.world.layer.Layer;
public class LayerGenCaves extends LayerGen
{
@Override
public double getTemperatureStatic(Layer layer, Vec2d pos)
{
// Get the noise generator
@ -32,11 +30,10 @@ public class LayerGenCaves extends LayerGen
}
@Override
public double getTemperatureDynamic(Layer layer, Vec2d pos) {
public double getTemperature(Layer layer, Vec2d pos) {
return getTemperatureStatic(layer, pos);
}
@Override
public double getHumidity(Layer layer, Vec2d pos)
{
// Get the noise generator

View File

@ -30,7 +30,6 @@ public class LayerGenEarth extends LayerGen
layer.noise_gens[3].eval(pos.x / 64.0, pos.y / 64.0, t) * 0.02);
}
@Override
public double getTemperatureStatic(Layer layer, Vec2d pos)
{
// Get the noise generator
@ -39,7 +38,7 @@ public class LayerGenEarth extends LayerGen
}
@Override
public double getTemperatureDynamic(Layer layer, Vec2d pos)
public double getTemperature(Layer layer, Vec2d pos)
{
// Get the noise generator
double humidity = getHumidity(layer, pos);
@ -50,7 +49,6 @@ public class LayerGenEarth extends LayerGen
return MathHelpers.map(terrain_noise.eval(pos.x / World.BIOME_SIZE, pos.y / World.BIOME_SIZE), -1, 1, 0, 0.5 + light);
}
@Override
public double getHumidity(Layer layer, Vec2d pos)
{
// Get the noise generator
@ -67,8 +65,8 @@ public class LayerGenEarth extends LayerGen
layer.noise_gens = new NoiseGenerator[]
{
new NoiseGeneratorSimplex(rand, 64), // Temperature
new NoiseGeneratorSimplex(rand, 64), // Humidity
new NoiseGeneratorSimplex(rand, 4), // Temperature
new NoiseGeneratorSimplex(rand, 4), // Humidity
new NoiseGeneratorSimplex(lrand), // Wind
new NoiseGeneratorSimplex(lrand), // Wind

View File

@ -178,18 +178,8 @@ public class LayerGenLavaCaves extends LayerGen
}
@Override
public double getTemperatureStatic(Layer layer, Vec2d pos) {
public double getTemperature(Layer layer, Vec2d pos) {
return MathHelpers.map(layer.noise_gens[0].eval(pos.x / 128, pos.y / 128), -1, 1, 0.8, 1);
}
@Override
public double getTemperatureDynamic(Layer layer, Vec2d pos) {
return getTemperatureStatic(layer, pos);
}
@Override
public double getHumidity(Layer layer, Vec2d pos) {
return 0;
}
}