diff --git a/src/main/java/com/github/halotroop/litecraft/Litecraft.java b/src/main/java/com/github/halotroop/litecraft/Litecraft.java index ce0a96c..59bb855 100644 --- a/src/main/java/com/github/halotroop/litecraft/Litecraft.java +++ b/src/main/java/com/github/halotroop/litecraft/Litecraft.java @@ -58,8 +58,10 @@ public class Litecraft extends Game if (this.world != null) { System.out.println("Saving chunks..."); + long time = System.currentTimeMillis(); this.world.unloadAllChunks(); this.getSave().saveGlobalData(this.world.getSeed(), this.player); + System.out.println("Saved world in " + (System.currentTimeMillis() - time) + " milliseconds"); } engine.cleanup(); System.exit(0); diff --git a/src/main/java/com/github/halotroop/litecraft/save/LitecraftSave.java b/src/main/java/com/github/halotroop/litecraft/save/LitecraftSave.java index c18672c..7c5d6df 100644 --- a/src/main/java/com/github/halotroop/litecraft/save/LitecraftSave.java +++ b/src/main/java/com/github/halotroop/litecraft/save/LitecraftSave.java @@ -159,5 +159,5 @@ public final class LitecraftSave } private static final String SAVE_DIR = "./saves/"; - private static final int RENDER_SIZE = 10; + private static final int RENDER_SIZE = 5; } diff --git a/src/main/java/com/github/halotroop/litecraft/screens/IngameHUD.java b/src/main/java/com/github/halotroop/litecraft/screens/IngameHUD.java index 236e2b0..07bdb86 100644 --- a/src/main/java/com/github/halotroop/litecraft/screens/IngameHUD.java +++ b/src/main/java/com/github/halotroop/litecraft/screens/IngameHUD.java @@ -32,10 +32,14 @@ public class IngameHUD extends Screen @Override public void tick() { +// long maxMemory = Runtime.getRuntime().maxMemory(); + long totalMemory = Runtime.getRuntime().totalMemory(); + long freeMemory = Runtime.getRuntime().freeMemory(); + long usedMemory = totalMemory - freeMemory; Vector4i dbg = litecraft.dbgStats; Vector3f position = GingerRegister.getInstance().game.data.player.getPosition(); - debugText.setText("FPS: " + dbg.x() + " UPS: " + dbg.y + " TPS: " + dbg.z); - positionText.setText("Position " + (int) position.x() + ", " + (int) position.y() + ", "+ (int) position.z()); + debugText.setText("FPS: " + dbg.x() + " UPS: " + dbg.y + " TPS: " + dbg.z + " Mem: " + (usedMemory / 1024 / 1024) + "MB / " + (totalMemory / 1024 / 1024) + " MB"); + positionText.setText("Position " + (int) position.x() + ", " + (int) position.y() + ", "+ (int) position.z() ); } @Override diff --git a/src/main/java/com/github/halotroop/litecraft/world/Chunk.java b/src/main/java/com/github/halotroop/litecraft/world/Chunk.java index 630b1b9..47ef145 100644 --- a/src/main/java/com/github/halotroop/litecraft/world/Chunk.java +++ b/src/main/java/com/github/halotroop/litecraft/world/Chunk.java @@ -1,6 +1,6 @@ package com.github.halotroop.litecraft.world; -import java.util.Arrays; +import java.util.*; import java.util.function.ToIntFunction; import org.joml.Vector3f; @@ -20,19 +20,24 @@ public class Chunk implements BlockAccess, WorldGenConstants, SODSerializable * @param x in-chunk x coordinate. * @param y in-chunk y coordinate. * @param z in-chunk z coordinate. - * @return creates a long that represents a coordinate, for use as a key in the array. + * @return creates a long that represents a coordinate, for use as a key in arrays. */ public static int index(int x, int y, int z) { return (x & MAX_POS) | ((y & MAX_POS) << POS_SHIFT) | ((z & MAX_POS) << DOUBLE_SHIFT); } private final Block[] blocks = new Block[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE]; - private BlockInstance[] blockEntities = new BlockInstance[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE]; + private BlockInstance[] blockInstances = new BlockInstance[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE]; private boolean shouldRender = false; public final int chunkX, chunkY, chunkZ; public final int chunkStartX, chunkStartY, chunkStartZ; private boolean fullyGenerated = false; public final int dimension; private boolean dirty = true; + private World world; + /** + * A holder for the rendered blocks in this chunk. This array is *NOT* safe to use for getting BIs at a position! + * It can vary in size from 0 to 512 elements long and must only be read linearly. + */ private BlockInstance[] renderedBlocks = new BlockInstance[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE]; public Chunk(World world, int chunkX, int chunkY, int chunkZ, int dimension) @@ -63,8 +68,8 @@ public class Chunk implements BlockAccess, WorldGenConstants, SODSerializable public BlockInstance getBlockInstance(int x, int y, int z) { if (x > CHUNK_SIZE || y > CHUNK_SIZE || z > CHUNK_SIZE || x < 0 || y < 0 || z < 0) - { throw new RuntimeException("Block [" + x + ", " + y + ", " + z + "] out of chunk bounds!"); } - return this.blockEntities[index(x, y, z)]; + { throw new RuntimeException("BlockInstance [" + x + ", " + y + ", " + z + "] out of chunk bounds!"); } + return this.blockInstances[index(x, y, z)]; } public void render(BlockRenderer blockRenderer) @@ -72,7 +77,9 @@ public class Chunk implements BlockAccess, WorldGenConstants, SODSerializable if (shouldRender) { if (dirty) + { dirty = false; + List tempList = new ArrayList<>(); Arrays.fill(renderedBlocks, null); for (int x = 0; x < CHUNK_SIZE; x++) for (int y = 0; y < CHUNK_SIZE; y++) @@ -80,19 +87,35 @@ public class Chunk implements BlockAccess, WorldGenConstants, SODSerializable { BlockInstance block = getBlockInstance(x, y, z); - // Why are we deliberately rendering blocks on the outside of the chunk??? + // Check for chunk edges to avoid errors when get the neighboring blocks, TODO fix this if (x == 0 || x == CHUNK_SIZE - 1 || z == 0 || z == CHUNK_SIZE - 1 || y == 0 || y == CHUNK_SIZE - 1) { - renderedBlocks[index(x, y, z)] = block; + tempList.add(block); continue; } - // Check for non-full-cubes around the block - if ((!getBlock(x - 1, y, z).isFullCube() || !getBlock(x + 1, y, z).isFullCube() || !getBlock(x, y - 1, z).isFullCube() - || !getBlock(x, y + 1, z).isFullCube() || !getBlock(x, y, z - 1).isFullCube() || !getBlock(x, y, z + 1).isFullCube())) - renderedBlocks[index(x, y, z)] = block; + + // Check for air. Yes this is stupid, TODO fix this too + try + { + if (getBlockInstance(x - 1, y, z).getModel() == null || getBlockInstance(x + 1, y, z).getModel() == null || + getBlockInstance(x, y - 1, z).getModel() == null || getBlockInstance(x, y + 1, z).getModel() == null || + getBlockInstance(x, y, z - 1).getModel() == null || getBlockInstance(x, y, z + 1).getModel() == null) + { + tempList.add(block); + } + } catch (NullPointerException e) + { // this seems to be a hotspot for errors + e.printStackTrace(); // so I can add a debug breakpoint on this line + throw e; // e + } } + renderedBlocks = tempList.toArray(BlockInstance[]::new); + } + + blockRenderer.prepareRender(); blockRenderer.render(renderedBlocks); + blockRenderer.shader.stop(); } } @@ -113,7 +136,7 @@ public class Chunk implements BlockAccess, WorldGenConstants, SODSerializable else if (z < 0) z = 0; // this.blocks[index(x, y, z)] = block; - if (this.shouldRender) this.blockEntities[index(x, y, z)] = + if (this.shouldRender) this.blockInstances[index(x, y, z)] = new BlockInstance(block, new Vector3f(this.chunkStartX + x, this.chunkStartY + y, this.chunkStartZ + z)); dirty = true; } @@ -130,7 +153,7 @@ public class Chunk implements BlockAccess, WorldGenConstants, SODSerializable { Block block = this.blocks[index(x, y, z)]; - this.blockEntities[index(x, y, z)] = new BlockInstance(block, + this.blockInstances[index(x, y, z)] = new BlockInstance(block, new Vector3f( this.chunkStartX + x, this.chunkStartY + y, @@ -139,7 +162,7 @@ public class Chunk implements BlockAccess, WorldGenConstants, SODSerializable else if (!render && this.shouldRender) // else if it has been changed to false. // we need to check both variables because there are two cases that make // the if statement fall to here - blockEntities = new BlockInstance[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE]; + blockInstances = new BlockInstance[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE]; this.shouldRender = render; dirty = true; } diff --git a/src/main/java/com/github/halotroop/litecraft/world/DynamicChunkLoader.java b/src/main/java/com/github/halotroop/litecraft/world/DynamicChunkLoader.java deleted file mode 100644 index dbc5482..0000000 --- a/src/main/java/com/github/halotroop/litecraft/world/DynamicChunkLoader.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.github.halotroop.litecraft.world; - -import java.util.*; -import java.util.function.LongConsumer; - -import com.github.hydos.multithreading.GingerThread; - -import it.unimi.dsi.fastutil.longs.*; - -public class DynamicChunkLoader extends GingerThread -{ - - private static int instances = 0; - public int chunkX, chunkY, chunkZ; - public World world; - - public DynamicChunkLoader(int chunkX, int chunkY, int chunkZ, World world) - { - this.chunkX = chunkX; - this.chunkY = chunkY; - this.chunkZ = chunkZ; - this.world = world; - this.setName("Dynamic Chunk thread"); - instances++; - System.out.println("allocations of dynamic chunk loader: " + instances); - } - - @Override - public void run() - { - Long2ObjectMap chunks = world.chunks; //this is to seperate the lists so we dont create render bugs - - started = true; - List toKeep = new ArrayList<>(); - // loop over rendered area, adding chunks that are needed - for (int x = chunkX - this.world.renderBound; x < chunkX + this.world.renderBound; x++) - for (int z = chunkZ - this.world.renderBound; z < chunkZ + this.world.renderBound; z++) - for (int y = chunkY - this.world.renderBound; y < chunkY + this.world.renderBound; y++) - toKeep.add(this.world.getChunkToLoad(x, y, z)); - // list of keys to remove - LongList toRemove = new LongArrayList(); - // check which loaded chunks are not neccesary - chunks.forEach((pos, chunk) -> - { - if (!toKeep.contains(chunk)) - toRemove.add((long) pos); - }); - // unload unneccesary chunks from chunk array - toRemove.forEach((LongConsumer) pos -> this.world.unloadChunk(pos)); - // populate chunks to render if they are not rendered, then render them - toKeep.forEach(chunk -> { - if (!chunk.isFullyGenerated()) - { - this.world.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) - chunks.put(this.world.posHash(chunk.chunkX, chunk.chunkY, chunk.chunkZ), chunk); - }); - this.world.chunks = chunks; - this.finished = true; - } - -} diff --git a/src/main/java/com/github/halotroop/litecraft/world/World.java b/src/main/java/com/github/halotroop/litecraft/world/World.java index 3d790ab..bfb7e4b 100644 --- a/src/main/java/com/github/halotroop/litecraft/world/World.java +++ b/src/main/java/com/github/halotroop/litecraft/world/World.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ForkJoinPool; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.LongConsumer; @@ -30,6 +31,7 @@ public class World implements BlockAccess, WorldGenConstants private final LitecraftSave save; private final long seed; private final int dimension; + private final ForkJoinPool threadPool; public Player player; int renderBound; int renderBoundVertical; @@ -37,7 +39,7 @@ public class World implements BlockAccess, WorldGenConstants private final BlockInstance dummy; public World(long seed, int renderSize, Dimension dim, LitecraftSave save) { - new DynamicChunkLoader(0, 0, 0, this); + this.threadPool = new ForkJoinPool(4, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); this.dummy = new BlockInstance(Blocks.ANDESITE, new Vector3f(0, 0, 0)); this.dummy.setVisible(false); this.chunks = new Long2ObjectArrayMap<>(); @@ -65,7 +67,7 @@ public class World implements BlockAccess, WorldGenConstants int y = SEA_LEVEL; int attemptsRemaining = 255; - while (attemptsRemaining --> 0) + while (attemptsRemaining-- > 0) { // DO NOT CHANGE TO y++ if (this.getBlock(x, ++y, z) == Blocks.AIR) @@ -136,10 +138,11 @@ public class World implements BlockAccess, WorldGenConstants if (chunk == null) return false; // Otherwise save the chunk AtomicBoolean result = new AtomicBoolean(false); - CompletableFuture.runAsync(() -> { + CompletableFuture.runAsync(() -> + { result.set(this.save.saveChunk(chunk)); this.chunks.remove(posHash); - }); + }, threadPool); return result.get(); } @@ -180,19 +183,33 @@ public class World implements BlockAccess, WorldGenConstants public void render(BlockRenderer blockRenderer) { blockRenderer.prepareModel(this.dummy.getModel()); - this.chunks.forEach((pos, c) -> c.render(blockRenderer)); + try + { + this.chunks.forEach((pos, c) -> c.render(blockRenderer)); + } + catch (NullPointerException e) + { + System.out.println("Null chunk - we should look into fixing this"); + } blockRenderer.unbindModel(); } public void unloadAllChunks() { LongList chunkPositions = new LongArrayList(); + List futures = new ArrayList<>(); if (this.chunks != null) + { this.chunks.forEach((pos, chunk) -> { // for every chunk in memory - chunkPositions.add((long) pos); // add pos to chunk positions list for removal later - this.save.saveChunk(chunk); // save chunk + futures.add(CompletableFuture.runAsync(() -> + { + chunkPositions.add((long) pos); // add pos to chunk positions list for removal later + this.save.saveChunk(chunk); // save chunk + }, threadPool)); }); + } + futures.forEach(CompletableFuture::join); chunkPositions.forEach((LongConsumer) (pos -> this.chunks.remove(pos))); // remove all chunks } @@ -203,43 +220,38 @@ public class World implements BlockAccess, WorldGenConstants public void updateLoadedChunks(int chunkX, int chunkY, int chunkZ) { - //AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - //Ginger.getInstance().threading.registerChunkThreadToWaitlist(new DynamicChunkLoader(chunkX, chunkY, chunkZ, this)); - - Long2ObjectMap chunksList = this.chunks; - - //FIXME completable futures - - List toKeep = new ArrayList<>(); - // loop over rendered area, adding chunks that are needed - for (int x = chunkX - this.renderBound; x < chunkX + this.renderBound; x++) - for (int z = chunkZ - this.renderBound; z < chunkZ + this.renderBound; z++) - for (int y = chunkY - this.renderBound; y < chunkY + this.renderBound; y++) - toKeep.add(this.getChunkToLoad(x, y, z)); - - LongList toRemove = new LongArrayList(); - // check which loaded chunks are not neccesary - chunksList.forEach((pos, chunk) -> + CompletableFuture.runAsync(() -> { - if (!toKeep.contains(chunk)) - toRemove.add((long) pos); - }); - // unload unneccesary chunks from chunk array - toRemove.forEach((LongConsumer) this::unloadChunk); + List toKeep = new ArrayList<>(); + // loop over rendered area, adding chunks that are needed + for (int x = chunkX - this.renderBound; x < chunkX + this.renderBound; x++) + for (int z = chunkZ - this.renderBound; z < chunkZ + this.renderBound; z++) + for (int y = chunkY - this.renderBound; y < chunkY + this.renderBound; y++) + toKeep.add(this.getChunkToLoad(x, y, z)); - toKeep.forEach(chunk -> { - if (!chunk.isFullyGenerated()) + LongList toRemove = new LongArrayList(); + // check which loaded chunks are not neccesary + chunks.forEach((pos, chunk) -> { - 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) - chunksList.put(this.posHash(chunk.chunkX, chunk.chunkY, chunk.chunkZ), chunk); - }); - this.chunks = chunksList; + if (!toKeep.contains(chunk)) + toRemove.add((long) pos); + }); + // unload unneccesary chunks from chunk array + toRemove.forEach((LongConsumer) this::unloadChunk); + 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) + chunks.put(this.posHash(chunk.chunkX, chunk.chunkY, chunk.chunkZ), chunk); + }); + }, threadPool); } private static final class GenerationWorld implements BlockAccess, WorldGenConstants diff --git a/src/main/java/com/github/halotroop/litecraft/world/block/BlockRenderer.java b/src/main/java/com/github/halotroop/litecraft/world/block/BlockRenderer.java index 7cdefda..ed9f30e 100644 --- a/src/main/java/com/github/halotroop/litecraft/world/block/BlockRenderer.java +++ b/src/main/java/com/github/halotroop/litecraft/world/block/BlockRenderer.java @@ -4,7 +4,6 @@ import org.joml.Matrix4f; import org.lwjgl.opengl.*; import com.github.halotroop.litecraft.types.block.BlockInstance; -import com.github.halotroop.litecraft.world.Chunk; import com.github.halotroop.litecraft.world.gen.WorldGenConstants; import com.github.hydos.ginger.engine.common.api.GingerRegister; import com.github.hydos.ginger.engine.common.elements.objects.RenderObject; @@ -17,7 +16,7 @@ import com.github.hydos.ginger.engine.opengl.utils.GlLoader; public class BlockRenderer extends Renderer implements WorldGenConstants { - private StaticShader shader; + public StaticShader shader; public int atlasID; public BlockRenderer(StaticShader shader, Matrix4f projectionMatrix) @@ -76,21 +75,17 @@ public class BlockRenderer extends Renderer implements WorldGenConstants public void render(BlockInstance[] renderList) { prepareRender(); - for (int x = 0; x < CHUNK_SIZE; x++) - for (int y = 0; y < CHUNK_SIZE; y++) - for (int z = 0; z < CHUNK_SIZE; z++) - { - BlockInstance entity = renderList[Chunk.index(x, y, z)]; - if (entity != null && entity.getModel() != null) - { - TexturedModel blockModel = entity.getModel(); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, blockModel.getTexture().getTextureID()); - prepBlockInstance(entity); - GL11.glDrawElements(GL11.GL_TRIANGLES, blockModel.getRawModel().getVertexCount(), - GL11.GL_UNSIGNED_INT, 0); - } - } - disableWireframe(); - shader.stop(); + + for (BlockInstance entity : renderList) { + if (entity != null && entity.getModel() != null) + { + TexturedModel blockModel = entity.getModel(); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, blockModel.getTexture().getTextureID()); + prepBlockInstance(entity); + GL11.glDrawElements(GL11.GL_TRIANGLES, blockModel.getRawModel().getVertexCount(), GL11.GL_UNSIGNED_INT, 0); + } + } +// disableWireframe(); +// shader.stop(); } } diff --git a/src/main/java/com/github/halotroop/litecraft/world/gen/WorldGenConstants.java b/src/main/java/com/github/halotroop/litecraft/world/gen/WorldGenConstants.java index 9acd457..9beaf0c 100644 --- a/src/main/java/com/github/halotroop/litecraft/world/gen/WorldGenConstants.java +++ b/src/main/java/com/github/halotroop/litecraft/world/gen/WorldGenConstants.java @@ -2,7 +2,7 @@ package com.github.halotroop.litecraft.world.gen; public interface WorldGenConstants { - int POS_SHIFT = 3; + int POS_SHIFT = 4; int DOUBLE_SHIFT = POS_SHIFT * 2; int CHUNK_SIZE = (int) Math.pow(2, POS_SHIFT); int MAX_POS = CHUNK_SIZE - 1; diff --git a/src/main/java/com/github/halotroop/litecraft/world/gen/modifier/CavesModifier.java b/src/main/java/com/github/halotroop/litecraft/world/gen/modifier/CavesModifier.java index b1de6cf..0b854fa 100644 --- a/src/main/java/com/github/halotroop/litecraft/world/gen/modifier/CavesModifier.java +++ b/src/main/java/com/github/halotroop/litecraft/world/gen/modifier/CavesModifier.java @@ -10,7 +10,8 @@ import com.github.halotroop.litecraft.world.gen.WorldGenConstants; public class CavesModifier implements WorldModifier, WorldGenConstants { private OctaveSimplexNoise caveNoise; - // + private static final double THRESHOLD = 0.1; + @Override public void initialize(long seed) { diff --git a/src/main/java/com/github/hydos/ginger/engine/common/api/GingerRegister.java b/src/main/java/com/github/hydos/ginger/engine/common/api/GingerRegister.java index e4a8a4e..1b3b3c3 100644 --- a/src/main/java/com/github/hydos/ginger/engine/common/api/GingerRegister.java +++ b/src/main/java/com/github/hydos/ginger/engine/common/api/GingerRegister.java @@ -8,7 +8,6 @@ import com.github.hydos.ginger.engine.common.font.GUIText; import com.github.hydos.ginger.engine.common.screen.Screen; import com.github.hydos.ginger.engine.opengl.postprocessing.Fbo; import com.github.hydos.ginger.engine.opengl.render.MasterRenderer; -import com.github.hydos.multithreading.GingerThreading; /** Used if a game wants to access engine variables safely */ public class GingerRegister @@ -19,7 +18,6 @@ public class GingerRegister public static GingerRegister getInstance() { return INSTANCE; } - public GingerThreading threadRegister; public List texts; public List guiButtons; public List fbos; @@ -30,12 +28,11 @@ public class GingerRegister public GingerRegister() { INSTANCE = this; - threadRegister = new GingerThreading(); } public void registerButton(TextureButton button) { - if (guiButtons == null) guiButtons = new ArrayList(); + if (guiButtons == null) guiButtons = new ArrayList<>(); guiButtons.add(button); } @@ -44,7 +41,7 @@ public class GingerRegister public void registerText(GUIText guiText) { - if (texts == null) texts = new ArrayList(); + if (texts == null) texts = new ArrayList<>(); texts.add(guiText); } diff --git a/src/main/java/com/github/hydos/ginger/engine/opengl/api/GingerGL.java b/src/main/java/com/github/hydos/ginger/engine/opengl/api/GingerGL.java index bbc65e7..1478bc9 100644 --- a/src/main/java/com/github/hydos/ginger/engine/opengl/api/GingerGL.java +++ b/src/main/java/com/github/hydos/ginger/engine/opengl/api/GingerGL.java @@ -16,7 +16,6 @@ import com.github.hydos.ginger.engine.opengl.postprocessing.*; import com.github.hydos.ginger.engine.opengl.render.MasterRenderer; import com.github.hydos.ginger.engine.opengl.render.tools.MousePicker; import com.github.hydos.ginger.engine.opengl.utils.GlLoader; -import com.github.hydos.multithreading.GingerThreading; public class GingerGL { @@ -25,7 +24,6 @@ public class GingerGL public MousePicker picker; public FontType globalFont; public Fbo contrastFbo; - public GingerThreading threading; private Timer timer; TickListener gameTickListener = new TickListener() @@ -102,7 +100,6 @@ public class GingerGL { INSTANCE = this; registry = new GingerRegister(); - threading = new GingerThreading(); registry.registerGame(game); timer = new Timer(game.data.tickSpeed); timer.addTickListener(gameTickListener); @@ -114,15 +111,11 @@ public class GingerGL public void startGameLoop() { - if (!threading.isAlive()) // Prevents this from accidentally being run twice + while (!Window.closed()) { - threading.start(); - while (!Window.closed()) - { - update(Litecraft.getInstance().data); // Run this regardless, (so as fast as possible) - if (timer.tick()) Litecraft.getInstance().tps += 1; // Run this only [ticklimit] times per second (This invokes gameTickListener.onTick!) - if (Window.shouldRender()) registry.game.render(); // Run this only [framelimit] times per second - } + update(Litecraft.getInstance().data); // Run this regardless, (so as fast as possible) + if (timer.tick()) Litecraft.getInstance().tps += 1; // Run this only [ticklimit] times per second (This invokes gameTickListener.onTick!) + if (Window.shouldRender()) registry.game.render(); // Run this only [framelimit] times per second } registry.game.exit(); }