From 02daa8509786cf7f661eb53c4ef583a7afa691fd Mon Sep 17 00:00:00 2001 From: mcrcortex <18544518+MCRcortex@users.noreply.github.com> Date: Sun, 14 Jan 2024 14:00:32 +1000 Subject: [PATCH] Cleanup and ram limiting --- .../cortex/voxelmon/core/DistanceTracker.java | 2 +- .../me/cortex/voxelmon/core/VoxelCore.java | 16 ++- .../core/rendering/building/QuadFormat.java | 15 +- .../rendering/building/RenderDataFactory.java | 1 + .../building/RenderDataFactory2.java | 134 ++++++++++++++++++ .../voxelmon/core/util/TrackedObject.java | 15 +- .../voxelmon/importers/WorldImporter.java | 7 + 7 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 src/main/java/me/cortex/voxelmon/core/rendering/building/RenderDataFactory2.java diff --git a/src/main/java/me/cortex/voxelmon/core/DistanceTracker.java b/src/main/java/me/cortex/voxelmon/core/DistanceTracker.java index 1f1e97f5..937ecd17 100644 --- a/src/main/java/me/cortex/voxelmon/core/DistanceTracker.java +++ b/src/main/java/me/cortex/voxelmon/core/DistanceTracker.java @@ -29,7 +29,7 @@ public class DistanceTracker { this.tracker = tracker; this.scale = scale; - this.rings[0] = new TransitionRing2D(5, (int) MinecraftClient.getInstance().options.getClampedViewDistance()/2, (x, z)->{ + this.rings[0] = new TransitionRing2D(5, MinecraftClient.getInstance().options.getClampedViewDistance()/2, (x, z)->{ if (false) { return; } diff --git a/src/main/java/me/cortex/voxelmon/core/VoxelCore.java b/src/main/java/me/cortex/voxelmon/core/VoxelCore.java index 9531b8ed..75aff90a 100644 --- a/src/main/java/me/cortex/voxelmon/core/VoxelCore.java +++ b/src/main/java/me/cortex/voxelmon/core/VoxelCore.java @@ -69,20 +69,26 @@ public class VoxelCore { //private final Thread shutdownThread = new Thread(this::shutdown); public VoxelCore() { + System.out.println("Initializing voxel core"); + //Trigger the shared index buffer loading SharedIndexBuffer.INSTANCE.id(); this.renderer = new Gl46FarWorldRenderer(); - this.world = new WorldEngine(new File("storagefile2.db"), 2, 5, 5);//"storagefile.db"//"ethoslab.db" + System.out.println("Renderer initialized"); + this.world = new WorldEngine(new File("storagefile.db"), 2, 15, 5);//"storagefile.db"//"ethoslab.db" + System.out.println("World engine"); this.renderTracker = new RenderTracker(this.world, this.renderer); this.renderGen = new RenderGenerationService(this.world,5, this.renderTracker::processBuildResult); this.world.setRenderTracker(this.renderTracker); this.renderTracker.setRenderGen(this.renderGen); + System.out.println("Render tracker and generator initialized"); //To get to chunk scale multiply the scale by 2, the scale is after how many chunks does the lods halve this.distanceTracker = new DistanceTracker(this.renderTracker, 5, 16);//20 + System.out.println("Distance tracker initialized"); - this.postProcessing = new PostProcessing(); + this.postProcessing = null;//new PostProcessing(); this.world.getMapper().setCallbacks(this::stateUpdate, this::biomeUpdate); @@ -101,6 +107,10 @@ public class VoxelCore { for (var biome : this.world.getMapper().getBiomeEntries()) { this.biomeUpdate(biome); } + System.out.println("Entry updates applied"); + + + System.out.println("Voxel core initialized"); } private void stateUpdate(Mapper.StateEntry entry) { @@ -188,7 +198,7 @@ public class VoxelCore { try {this.renderGen.shutdown();} catch (Exception e) {System.err.println(e);} try {this.world.shutdown();} catch (Exception e) {System.err.println(e);} try {this.renderer.shutdown();} catch (Exception e) {System.err.println(e);} - try {this.postProcessing.shutdown();} catch (Exception e) {System.err.println(e);} + if (this.postProcessing!=null){try {this.postProcessing.shutdown();} catch (Exception e) {System.err.println(e);}} } public WorldImporter createWorldImporter(World mcWorld, File worldPath) { diff --git a/src/main/java/me/cortex/voxelmon/core/rendering/building/QuadFormat.java b/src/main/java/me/cortex/voxelmon/core/rendering/building/QuadFormat.java index bf51bb3b..bca48afd 100644 --- a/src/main/java/me/cortex/voxelmon/core/rendering/building/QuadFormat.java +++ b/src/main/java/me/cortex/voxelmon/core/rendering/building/QuadFormat.java @@ -77,7 +77,18 @@ public class QuadFormat { return ((id>>>27)<<26)|Integer.toUnsignedLong(encodedPosition); } - public static long encode(Mapper mapper, long id, int face, int other, int encodedMeshedData) { - return encode(mapper, id, encodePosition(face, other, encodedMeshedData)); + public static long encode(Mapper mapper, long id, int face, int otherAxis, int encodedMeshedData) { + return encode(mapper, id, encodePosition(face, otherAxis, encodedMeshedData)); + } + + + + private static long encodeV2(Mapper mapper, long id, int face, int otherAxis, int encodedMeshedData) { + int position = encodePosition(face, otherAxis, encodedMeshedData); + int lighting = (int) ((id>>56)&0xFF); + int biome = (int) ((id>>47)&((1<<9)-1)); + int blockstate = (int) ((id>>20)&((1<<20)-1)); + + return -1; } } diff --git a/src/main/java/me/cortex/voxelmon/core/rendering/building/RenderDataFactory.java b/src/main/java/me/cortex/voxelmon/core/rendering/building/RenderDataFactory.java index b9f1d37c..ef3a6037 100644 --- a/src/main/java/me/cortex/voxelmon/core/rendering/building/RenderDataFactory.java +++ b/src/main/java/me/cortex/voxelmon/core/rendering/building/RenderDataFactory.java @@ -76,6 +76,7 @@ public class RenderDataFactory { continue; } } + //Recodes the id to include the correct lighting this.mesher.put(x, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); } } diff --git a/src/main/java/me/cortex/voxelmon/core/rendering/building/RenderDataFactory2.java b/src/main/java/me/cortex/voxelmon/core/rendering/building/RenderDataFactory2.java new file mode 100644 index 00000000..bf4d7d53 --- /dev/null +++ b/src/main/java/me/cortex/voxelmon/core/rendering/building/RenderDataFactory2.java @@ -0,0 +1,134 @@ +package me.cortex.voxelmon.core.rendering.building; + +import it.unimi.dsi.fastutil.longs.LongArrayList; +import me.cortex.voxelmon.core.util.MemoryBuffer; +import me.cortex.voxelmon.core.util.Mesher2D; +import me.cortex.voxelmon.core.world.WorldEngine; +import me.cortex.voxelmon.core.world.WorldSection; +import me.cortex.voxelmon.core.world.other.Mapper; +import net.minecraft.util.math.Direction; +import org.lwjgl.system.MemoryUtil; + + +public class RenderDataFactory2 { + private final Mesher2D[] meshers = new Mesher2D[6]; + private final LongArrayList outData = new LongArrayList(1000); + private final WorldEngine world; + private final long[] sectionCache = new long[32*32*32]; + private final long[][] connectedSectionCaches = new long[6][32*32*32]; + + public RenderDataFactory2(WorldEngine world) { + this.world = world; + for (int i = 0; i < this.meshers.length; i++) { + this.meshers[i] = new Mesher2D(5, 15); + } + } + + //TODO: MAKE a render cache that caches each WorldSection directional face generation, cause then can just pull that directly + // instead of needing to regen the entire thing + + //section is already acquired and gets released by the parent + + //buildMask in the lower 6 bits contains the faces to build, the next 6 bits are whether the edge face builds against + // its neigbor or not (0 if it does 1 if it doesnt (0 is default behavior)) + + public BuiltSectionGeometry generateMesh2(WorldSection section, int buildMask) { + //TODO: to speed it up more, check like section.isEmpty() and stuff like that, have masks for if a slice/layer is entirly air etc + + //TODO: instead of having it check its neighbors with the same lod level, compare against 1 level lower, this will prevent cracks and seams from + // appearing between lods + + + //if (section.definitelyEmpty()) {//Fast path if its known the entire chunk is empty + // return new BuiltSectionGeometry(section.getKey(), null, null); + //} + + section.copyDataTo(this.sectionCache); + var data = this.sectionCache; + + long[][] localConnections = new long[6][]; + + for (int y = 0; y < 32; y++) { + for (int z = 0; z < 32; z++) { + for (int x = 0; x < 32; x++) { + var self = data[WorldSection.getIndex(x, y, z)]; + if (Mapper.isAir(self)) { + continue; + } + + //TODO: FInish + // whats missing/is an issue is that having multiple meshers at once with an arbitary render direction doesnt really work + // Need to majorly fix this, cause atm meshing is taking 90% of the render time + + {//Up (y+) + var dir = Direction.UP.getId(); + if ((buildMask & (1 << dir)) != 0) { + long up = Mapper.AIR; + if (y < 31) { + up = data[WorldSection.getIndex(x, y + 1, z)]; + } else if (((buildMask >> (6 + dir)) & 1) == 0) {//This is to check with the build flags if it should build with respect to the neighboring chunk section + var connectedData = localConnections[dir]; + if (connectedData == null) { + var connectedSection = this.world.acquire(section.lvl, section.x, section.y + 1, section.z); + connectedData = localConnections[dir] = this.connectedSectionCaches[dir]; + connectedSection.copyDataTo(connectedData); + connectedSection.release(); + } + up = connectedData[WorldSection.getIndex(x, 0, z)]; + } + + + if (Mapper.shouldRenderFace(dir, self, up)) { + this.meshers[dir].put(x, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); + } + } + } + /* + long up = -1; + if (y < 31) { + up = data[WorldSection.getIndex(x, y + 1, z)]; + if (!Mapper.isTranslucent(up)) { + continue; + } + } + if (y == 31 && ((buildMask>>(6+dirId))&1) == 0) { + //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies + if (connectedData == null) { + var connectedSection = this.world.acquire(section.lvl, section.x, section.y + 1, section.z); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; + connectedSection.release(); + } + up = connectedData[WorldSection.getIndex(x, 0, z)]; + if (!Mapper.isTranslucent(up)) { + continue; + } + } + this.mesher.put(x, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); + } + + } + + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; + this.outData.add(QuadFormat.encode(null, this.mesher.getDataFromQuad(quad), 1, y, quad)); + */ + } + } + } + + if (this.outData.isEmpty()) { + return new BuiltSectionGeometry(section.getKey(), null, null); + } + + var output = new MemoryBuffer(this.outData.size()*8L); + for (int i = 0; i < this.outData.size(); i++) { + MemoryUtil.memPutLong(output.address + i * 8L, this.outData.getLong(i)); + } + + this.outData.clear(); + return new BuiltSectionGeometry(section.getKey(), output, null); + } +} diff --git a/src/main/java/me/cortex/voxelmon/core/util/TrackedObject.java b/src/main/java/me/cortex/voxelmon/core/util/TrackedObject.java index 93390600..c0e86623 100644 --- a/src/main/java/me/cortex/voxelmon/core/util/TrackedObject.java +++ b/src/main/java/me/cortex/voxelmon/core/util/TrackedObject.java @@ -33,13 +33,22 @@ public abstract class TrackedObject { private static final Cleaner cleaner = Cleaner.create(); public static Ref register(Object obj) { String clazz = obj.getClass().getName(); - Throwable trace = new Throwable(); - trace.fillInStackTrace(); + Throwable trace; + if (true) { + trace = new Throwable(); + trace.fillInStackTrace(); + } else { + trace = null; + } boolean[] freed = new boolean[1]; var clean = cleaner.register(obj, ()->{ if (!freed[0]) { System.err.println("Object named: "+ clazz+" was not freed, location at:\n"); - trace.printStackTrace(); + if (trace != null) { + trace.printStackTrace(); + } else { + System.err.println("Enable error tracing"); + } System.err.flush(); } }); diff --git a/src/main/java/me/cortex/voxelmon/importers/WorldImporter.java b/src/main/java/me/cortex/voxelmon/importers/WorldImporter.java index 165fe321..e2a39f82 100644 --- a/src/main/java/me/cortex/voxelmon/importers/WorldImporter.java +++ b/src/main/java/me/cortex/voxelmon/importers/WorldImporter.java @@ -190,6 +190,13 @@ public class WorldImporter { ); this.world.insertUpdate(csec); + while (this.world.savingService.getTaskCount() > 1500) { + try { + Thread.sleep(250); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } } }