Cleanup and ram limiting
This commit is contained in:
@@ -29,7 +29,7 @@ public class DistanceTracker {
|
|||||||
this.tracker = tracker;
|
this.tracker = tracker;
|
||||||
this.scale = scale;
|
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) {
|
if (false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,20 +69,26 @@ public class VoxelCore {
|
|||||||
//private final Thread shutdownThread = new Thread(this::shutdown);
|
//private final Thread shutdownThread = new Thread(this::shutdown);
|
||||||
|
|
||||||
public VoxelCore() {
|
public VoxelCore() {
|
||||||
|
System.out.println("Initializing voxel core");
|
||||||
|
|
||||||
//Trigger the shared index buffer loading
|
//Trigger the shared index buffer loading
|
||||||
SharedIndexBuffer.INSTANCE.id();
|
SharedIndexBuffer.INSTANCE.id();
|
||||||
this.renderer = new Gl46FarWorldRenderer();
|
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.renderTracker = new RenderTracker(this.world, this.renderer);
|
||||||
this.renderGen = new RenderGenerationService(this.world,5, this.renderTracker::processBuildResult);
|
this.renderGen = new RenderGenerationService(this.world,5, this.renderTracker::processBuildResult);
|
||||||
this.world.setRenderTracker(this.renderTracker);
|
this.world.setRenderTracker(this.renderTracker);
|
||||||
this.renderTracker.setRenderGen(this.renderGen);
|
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
|
//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
|
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);
|
this.world.getMapper().setCallbacks(this::stateUpdate, this::biomeUpdate);
|
||||||
|
|
||||||
@@ -101,6 +107,10 @@ public class VoxelCore {
|
|||||||
for (var biome : this.world.getMapper().getBiomeEntries()) {
|
for (var biome : this.world.getMapper().getBiomeEntries()) {
|
||||||
this.biomeUpdate(biome);
|
this.biomeUpdate(biome);
|
||||||
}
|
}
|
||||||
|
System.out.println("Entry updates applied");
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println("Voxel core initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stateUpdate(Mapper.StateEntry entry) {
|
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.renderGen.shutdown();} catch (Exception e) {System.err.println(e);}
|
||||||
try {this.world.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.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) {
|
public WorldImporter createWorldImporter(World mcWorld, File worldPath) {
|
||||||
|
|||||||
@@ -77,7 +77,18 @@ public class QuadFormat {
|
|||||||
return ((id>>>27)<<26)|Integer.toUnsignedLong(encodedPosition);
|
return ((id>>>27)<<26)|Integer.toUnsignedLong(encodedPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long encode(Mapper mapper, long id, int face, int other, int encodedMeshedData) {
|
public static long encode(Mapper mapper, long id, int face, int otherAxis, int encodedMeshedData) {
|
||||||
return encode(mapper, id, encodePosition(face, other, 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ public class RenderDataFactory {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//Recodes the id to include the correct lighting
|
||||||
this.mesher.put(x, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56)));
|
this.mesher.put(x, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,13 +33,22 @@ public abstract class TrackedObject {
|
|||||||
private static final Cleaner cleaner = Cleaner.create();
|
private static final Cleaner cleaner = Cleaner.create();
|
||||||
public static Ref register(Object obj) {
|
public static Ref register(Object obj) {
|
||||||
String clazz = obj.getClass().getName();
|
String clazz = obj.getClass().getName();
|
||||||
Throwable trace = new Throwable();
|
Throwable trace;
|
||||||
trace.fillInStackTrace();
|
if (true) {
|
||||||
|
trace = new Throwable();
|
||||||
|
trace.fillInStackTrace();
|
||||||
|
} else {
|
||||||
|
trace = null;
|
||||||
|
}
|
||||||
boolean[] freed = new boolean[1];
|
boolean[] freed = new boolean[1];
|
||||||
var clean = cleaner.register(obj, ()->{
|
var clean = cleaner.register(obj, ()->{
|
||||||
if (!freed[0]) {
|
if (!freed[0]) {
|
||||||
System.err.println("Object named: "+ clazz+" was not freed, location at:\n");
|
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();
|
System.err.flush();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -190,6 +190,13 @@ public class WorldImporter {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.world.insertUpdate(csec);
|
this.world.insertUpdate(csec);
|
||||||
|
while (this.world.savingService.getTaskCount() > 1500) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(250);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user