start dynamic chunkloading. crashes.

pull/12/head
valoeghese 2020-02-28 22:42:00 +13:00
parent d1cc1443eb
commit 56d8c65e0e
3 changed files with 115 additions and 46 deletions

View File

@ -182,4 +182,9 @@ public class Litecraft extends Game
ginger3D.setGingerPlayer(this.world.player);
}
}
public World getWorld()
{
return this.world;
}
}

View File

@ -1,6 +1,6 @@
package com.github.halotroop.litecraft.world;
import java.util.Random;
import java.util.*;
import java.util.function.LongConsumer;
import org.joml.Vector3f;
@ -26,9 +26,9 @@ public class World implements BlockAccess, WorldGenConstants
private final long seed;
private final int dimension;
public Player player;
private final int renderSize;
// This will likely become the main public constructor after we add dynamic chunkloading
private World(long seed, Dimension<?> dim, LitecraftSave save)
public World(long seed, int renderSize, Dimension<?> dim, LitecraftSave save)
{
this.chunks = new Long2ObjectArrayMap<>();
this.seed = seed;
@ -37,36 +37,7 @@ public class World implements BlockAccess, WorldGenConstants
this.genBlockAccess = new GenerationWorld(this);
this.save = save;
this.dimension = dim.id;
}
public void spawnPlayer()
{
int y = this.findAir(0, 0);
if (y == -1)
y = 300; // yeet
this.spawnPlayer(0, y, -3);
}
public Player spawnPlayer(float x, float y, float z)
{
TexturedModel dirtModel = ModelLoader.loadGenericCube("block/cubes/soil/dirt.png");
this.player = new Player(dirtModel, new Vector3f(x, y, z), 0, 180f, 0, new Vector3f(0.2f, 0.2f, 0.2f));
this.player.isVisible = false;
return this.player;
}
// this constructor will likely not be neccesary when we have dynamic chunkloading
public World(long seed, int size, Dimension<?> dim, LitecraftSave save)
{
this(seed, dim, save);
long time = System.currentTimeMillis();
System.out.println("Generating world!");
for (int i = (0 - (size / 2)); i < (size / 2); i++)
for (int k = (0 - (size / 2)); k < (size / 2); k++)
for (int y = -2; y < 2; ++y)
this.loadChunk(i, y, k).setRender(true);
System.out.println("Generated world in " + (System.currentTimeMillis() - time) + " milliseconds");
this.renderSize = renderSize;
}
public int findAir(int x, int z)
@ -84,6 +55,30 @@ public class World implements BlockAccess, WorldGenConstants
return -1; // if it fails, returns -1
}
public void spawnPlayer()
{
int y = this.findAir(0, 0);
if (y == -1)
y = 300; // yeet
this.spawnPlayer(0, y, -3);
}
public Player spawnPlayer(float x, float y, float z)
{
// Player model and stuff
TexturedModel dirtModel = ModelLoader.loadGenericCube("block/cubes/soil/dirt.png");
this.player = new Player(dirtModel, new Vector3f(x, y, z), 0, 180f, 0, new Vector3f(0.2f, 0.2f, 0.2f));
this.player.isVisible = false;
// Generate world around player
long time = System.currentTimeMillis();
System.out.println("Generating world!");
this.updateLoadedChunks(this.player.getChunkX(), this.player.getChunkY(), this.player.getChunkZ());
System.out.println("Generated world in " + (System.currentTimeMillis() - time) + " milliseconds");
// return player
return this.player;
}
public Chunk getChunk(int chunkX, int chunkY, int chunkZ)
{
Chunk chunk = this.chunks.computeIfAbsent(posHash(chunkX, chunkY, chunkZ), pos ->
@ -97,19 +92,21 @@ public class World implements BlockAccess, WorldGenConstants
return chunk;
}
public Chunk loadChunk(int chunkX, int chunkY, int chunkZ)
public Chunk getChunkToLoad(int chunkX, int chunkY, int chunkZ)
{
return this.chunks.computeIfAbsent(posHash(chunkX, chunkY, chunkZ), pos ->
{
Chunk readChunk = save.readChunk(chunkX, chunkY, chunkZ, this.dimension);
return readChunk == null ? this.chunkGenerator.generateChunk(chunkX, chunkY, chunkZ) : readChunk;
});
// try get an already loaded chunk
Chunk result = this.chunks.get(posHash(chunkX, chunkY, chunkZ));
if (result != null)
return result;
// try read a chunk from memory
result = save.readChunk(chunkX, chunkY, chunkZ, this.dimension);
// if neither of those work, generate the chunk
return result == null ? this.chunkGenerator.generateChunk(chunkX, chunkY, chunkZ) : result;
}
/** @return whether the chunk was unloaded without errors. Will often, but not always, be equal to whether the chunk was already in memory. */
public boolean unloadChunk(int chunkX, int chunkY, int chunkZ)
private boolean unloadChunk(long posHash)
{
long posHash = posHash(chunkX, chunkY, chunkZ);
Chunk chunk = this.chunks.get(posHash);
// If the chunk is not in memory, it does not need to be unloaded
if (chunk == null) return false;
@ -119,6 +116,11 @@ public class World implements BlockAccess, WorldGenConstants
return result;
}
private void populateChunk(Chunk chunk)
{
this.populateChunk(chunk.chunkX, chunk.chunkY, chunk.chunkZ, chunk.chunkStartX, chunk.chunkStartY, chunk.chunkStartZ);
}
private void populateChunk(int chunkX, int chunkY, int chunkZ, int chunkStartX, int chunkStartY, int chunkStartZ)
{
Random rand = new Random(this.seed + 5828671L * chunkX + -47245139L * chunkY + 8972357 * (long) chunkZ);
@ -176,6 +178,38 @@ public class World implements BlockAccess, WorldGenConstants
public static final int SEA_LEVEL = 0;
public void updateLoadedChunks(int newChunkX, int newChunkY, int newChunkZ)
{
List<Chunk> toKeep = new ArrayList<>();
// loop over rendered area, adding chunks that are needed
for (int x = -renderSize / 2; x < renderSize / 2; x++)
for (int z = -renderSize / 2; z < renderSize / 2; z++)
for (int y = -2; y < 2; ++y)
toKeep.add(this.getChunkToLoad(x, y, z));
// list of keys to remove
LongList toRemove = new LongArrayList();
// check which loaded chunks are not neccesary
this.chunks.forEach((pos, chunk) ->
{
if (!toKeep.contains(chunk))
toRemove.add((long) pos);
});
// unload unneccesary chunks from chunk array
toRemove.forEach((LongConsumer) pos -> this.unloadChunk(pos));
// populate chunks to render if they are not rendered, then render them
toKeep.forEach(chunk -> {
if (!chunk.isFullyGenerated())
{
this.populateChunk(chunk);
chunk.setFullyGenerated(true);
}
boolean alreadyRendering = chunk.doRender(); // if it's already rendering then it's most likely in the map
chunk.setRender(true);
if (!alreadyRendering)
this.chunks.put(posHash(chunk.chunkX, chunk.chunkY, chunk.chunkZ), chunk);
});
}
private static final class GenerationWorld implements BlockAccess, WorldGenConstants
{
GenerationWorld(World parent)

View File

@ -2,20 +2,29 @@ package com.github.hydos.ginger.engine.elements.objects;
import org.joml.Vector3f;
import com.github.halotroop.litecraft.Litecraft;
import com.github.halotroop.litecraft.util.RelativeDirection;
import com.github.halotroop.litecraft.world.World;
import com.github.halotroop.litecraft.world.gen.WorldGenConstants;
import com.github.hydos.ginger.engine.api.GingerRegister;
import com.github.hydos.ginger.engine.io.Window;
import com.github.hydos.ginger.engine.render.models.TexturedModel;
import com.github.hydos.ginger.main.settings.Constants;
public class Player extends RenderObject
public class Player extends RenderObject implements WorldGenConstants
{
private boolean isInAir = false;
private double upwardsSpeed;
private boolean noWeight = true; // because the force of gravity on an object's mass is called WEIGHT, not gravity
private int chunkX, chunkY, chunkZ;
public Player(TexturedModel model, Vector3f position, float rotX, float rotY, float rotZ, Vector3f scale)
{ super(model, position, rotX, rotY, rotZ, scale); }
{
super(model, position, rotX, rotY, rotZ, scale);
this.chunkX = (int) position.x >> POS_SHIFT;
this.chunkY = (int) position.y >> POS_SHIFT;
this.chunkZ = (int) position.z >> POS_SHIFT;
}
public void move(RelativeDirection direction)
{
@ -32,12 +41,12 @@ public class Player extends RenderObject
position.x -= Math.sin(ry) * Constants.movementSpeed;
break;
case LEFT:
ry -= NINETY_DEGREES;
ry -= RIGHT_ANGLE;
position.z -= Math.cos(ry) * Constants.movementSpeed;
position.x += Math.sin(ry) * Constants.movementSpeed;
break;
case RIGHT:
ry += NINETY_DEGREES;
ry += RIGHT_ANGLE;
position.z -= Math.cos(ry) * Constants.movementSpeed;
position.x += Math.sin(ry) * Constants.movementSpeed;
break;
@ -51,7 +60,7 @@ public class Player extends RenderObject
}
}
private static final float NINETY_DEGREES = (float) (Math.PI / 2f);
private static final float RIGHT_ANGLE = (float) (Math.PI / 2f);
private void jump()
{
@ -62,11 +71,32 @@ public class Player extends RenderObject
}
}
public int getChunkX()
{ return this.chunkX; }
public int getChunkY()
{ return this.chunkY; }
public int getChunkZ()
{ return this.chunkZ; }
public void updateMovement()
{
super.increasePosition(0, (float) (upwardsSpeed * (Window.getTime())), 0);
upwardsSpeed += Constants.gravity.y() * Window.getTime();
isInAir = false;
upwardsSpeed = 0;
int newChunkX = (int) position.x >> POS_SHIFT;
int newChunkY = (int) position.y >> POS_SHIFT;
int newChunkZ = (int) position.z >> POS_SHIFT;
if (newChunkX != this.chunkX || newChunkY != this.chunkY || newChunkZ != this.chunkZ)
{
Litecraft.getInstance().getWorld().updateLoadedChunks(newChunkX, newChunkY, newChunkZ);
this.chunkX = newChunkX;
this.chunkY = newChunkY;
this.chunkZ = newChunkZ;
}
}
}