start dynamic chunkloading. crashes.
parent
d1cc1443eb
commit
56d8c65e0e
|
@ -182,4 +182,9 @@ public class Litecraft extends Game
|
||||||
ginger3D.setGingerPlayer(this.world.player);
|
ginger3D.setGingerPlayer(this.world.player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public World getWorld()
|
||||||
|
{
|
||||||
|
return this.world;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package com.github.halotroop.litecraft.world;
|
package com.github.halotroop.litecraft.world;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.*;
|
||||||
import java.util.function.LongConsumer;
|
import java.util.function.LongConsumer;
|
||||||
|
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
@ -26,9 +26,9 @@ public class World implements BlockAccess, WorldGenConstants
|
||||||
private final long seed;
|
private final long seed;
|
||||||
private final int dimension;
|
private final int dimension;
|
||||||
public Player player;
|
public Player player;
|
||||||
|
private final int renderSize;
|
||||||
|
|
||||||
// This will likely become the main public constructor after we add dynamic chunkloading
|
public World(long seed, int renderSize, Dimension<?> dim, LitecraftSave save)
|
||||||
private World(long seed, Dimension<?> dim, LitecraftSave save)
|
|
||||||
{
|
{
|
||||||
this.chunks = new Long2ObjectArrayMap<>();
|
this.chunks = new Long2ObjectArrayMap<>();
|
||||||
this.seed = seed;
|
this.seed = seed;
|
||||||
|
@ -37,36 +37,7 @@ public class World implements BlockAccess, WorldGenConstants
|
||||||
this.genBlockAccess = new GenerationWorld(this);
|
this.genBlockAccess = new GenerationWorld(this);
|
||||||
this.save = save;
|
this.save = save;
|
||||||
this.dimension = dim.id;
|
this.dimension = dim.id;
|
||||||
}
|
this.renderSize = renderSize;
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int findAir(int x, int z)
|
public int findAir(int x, int z)
|
||||||
|
@ -84,6 +55,30 @@ public class World implements BlockAccess, WorldGenConstants
|
||||||
return -1; // if it fails, returns -1
|
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)
|
public Chunk getChunk(int chunkX, int chunkY, int chunkZ)
|
||||||
{
|
{
|
||||||
Chunk chunk = this.chunks.computeIfAbsent(posHash(chunkX, chunkY, chunkZ), pos ->
|
Chunk chunk = this.chunks.computeIfAbsent(posHash(chunkX, chunkY, chunkZ), pos ->
|
||||||
|
@ -97,19 +92,21 @@ public class World implements BlockAccess, WorldGenConstants
|
||||||
return chunk;
|
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 ->
|
// try get an already loaded chunk
|
||||||
{
|
Chunk result = this.chunks.get(posHash(chunkX, chunkY, chunkZ));
|
||||||
Chunk readChunk = save.readChunk(chunkX, chunkY, chunkZ, this.dimension);
|
if (result != null)
|
||||||
return readChunk == null ? this.chunkGenerator.generateChunk(chunkX, chunkY, chunkZ) : readChunk;
|
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. */
|
/** @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);
|
Chunk chunk = this.chunks.get(posHash);
|
||||||
// If the chunk is not in memory, it does not need to be unloaded
|
// If the chunk is not in memory, it does not need to be unloaded
|
||||||
if (chunk == null) return false;
|
if (chunk == null) return false;
|
||||||
|
@ -119,6 +116,11 @@ public class World implements BlockAccess, WorldGenConstants
|
||||||
return result;
|
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)
|
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);
|
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 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
|
private static final class GenerationWorld implements BlockAccess, WorldGenConstants
|
||||||
{
|
{
|
||||||
GenerationWorld(World parent)
|
GenerationWorld(World parent)
|
||||||
|
|
|
@ -2,20 +2,29 @@ package com.github.hydos.ginger.engine.elements.objects;
|
||||||
|
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import com.github.halotroop.litecraft.Litecraft;
|
||||||
import com.github.halotroop.litecraft.util.RelativeDirection;
|
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.api.GingerRegister;
|
||||||
import com.github.hydos.ginger.engine.io.Window;
|
import com.github.hydos.ginger.engine.io.Window;
|
||||||
import com.github.hydos.ginger.engine.render.models.TexturedModel;
|
import com.github.hydos.ginger.engine.render.models.TexturedModel;
|
||||||
import com.github.hydos.ginger.main.settings.Constants;
|
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 boolean isInAir = false;
|
||||||
private double upwardsSpeed;
|
private double upwardsSpeed;
|
||||||
private boolean noWeight = true; // because the force of gravity on an object's mass is called WEIGHT, not gravity
|
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)
|
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)
|
public void move(RelativeDirection direction)
|
||||||
{
|
{
|
||||||
|
@ -32,12 +41,12 @@ public class Player extends RenderObject
|
||||||
position.x -= Math.sin(ry) * Constants.movementSpeed;
|
position.x -= Math.sin(ry) * Constants.movementSpeed;
|
||||||
break;
|
break;
|
||||||
case LEFT:
|
case LEFT:
|
||||||
ry -= NINETY_DEGREES;
|
ry -= RIGHT_ANGLE;
|
||||||
position.z -= Math.cos(ry) * Constants.movementSpeed;
|
position.z -= Math.cos(ry) * Constants.movementSpeed;
|
||||||
position.x += Math.sin(ry) * Constants.movementSpeed;
|
position.x += Math.sin(ry) * Constants.movementSpeed;
|
||||||
break;
|
break;
|
||||||
case RIGHT:
|
case RIGHT:
|
||||||
ry += NINETY_DEGREES;
|
ry += RIGHT_ANGLE;
|
||||||
position.z -= Math.cos(ry) * Constants.movementSpeed;
|
position.z -= Math.cos(ry) * Constants.movementSpeed;
|
||||||
position.x += Math.sin(ry) * Constants.movementSpeed;
|
position.x += Math.sin(ry) * Constants.movementSpeed;
|
||||||
break;
|
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()
|
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()
|
public void updateMovement()
|
||||||
{
|
{
|
||||||
super.increasePosition(0, (float) (upwardsSpeed * (Window.getTime())), 0);
|
super.increasePosition(0, (float) (upwardsSpeed * (Window.getTime())), 0);
|
||||||
upwardsSpeed += Constants.gravity.y() * Window.getTime();
|
upwardsSpeed += Constants.gravity.y() * Window.getTime();
|
||||||
isInAir = false;
|
isInAir = false;
|
||||||
upwardsSpeed = 0;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue