E
This commit is contained in:
@@ -57,6 +57,6 @@ public class Test {
|
||||
//WorldEngine engine = new WorldEngine(new File("storagefile2.db"), 5);
|
||||
WorldImporter importer = new WorldImporter(null, null);
|
||||
//importer.importWorld(new File("run/saves/Drehmal 2.2 Apotheosis Beta - 1.0.0/region/"));
|
||||
importer.importWorldAsyncStart(new File("D:\\PrismLauncher-Windows-MSVC-Portable-7.1\\instances\\1.20.1(3)\\.minecraft\\.bobby\\build.docm77.de\\-8149132374211427218\\minecraft\\overworld\\"));
|
||||
importer.importWorldAsyncStart(new File("D:\\PrismLauncher-Windows-MSVC-Portable-7.1\\instances\\1.20.1(3)\\.minecraft\\.bobby\\build.docm77.de\\-8149132374211427218\\minecraft\\overworld\\"), 2,null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.cortex.voxelmon;
|
||||
|
||||
import me.cortex.voxelmon.terrain.TestSparseGenCommand;
|
||||
//import me.cortex.voxelmon.terrain.WorldImportCommand;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
@@ -8,6 +9,6 @@ import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
public class Voxelmon implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
//CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> TestSparseGenCommand.register(dispatcher));
|
||||
//CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> WorldImportCommand.register(dispatcher));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import net.minecraft.client.render.Frustum;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.WorldChunk;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
@@ -72,7 +73,7 @@ public class VoxelCore {
|
||||
//Trigger the shared index buffer loading
|
||||
SharedIndexBuffer.INSTANCE.id();
|
||||
this.renderer = new Gl46FarWorldRenderer();
|
||||
this.world = new WorldEngine(new File("storagefile2.db"), 20, 5);//"storagefile.db"//"ethoslab.db"
|
||||
this.world = new WorldEngine(new File("storagefile.db"), 20, 5);//"storagefile.db"//"ethoslab.db"
|
||||
|
||||
this.renderTracker = new RenderTracker(this.world, this.renderer);
|
||||
this.renderGen = new RenderGenerationService(this.world,4, this.renderTracker::processBuildResult);
|
||||
@@ -196,4 +197,12 @@ public class VoxelCore {
|
||||
try {this.renderer.shutdown();} catch (Exception e) {System.err.println(e);}
|
||||
try {this.postProcessing.shutdown();} catch (Exception e) {System.err.println(e);}
|
||||
}
|
||||
|
||||
public WorldImporter createWorldImporter(World mcWorld, File worldPath) {
|
||||
var importer = new WorldImporter(this.world, mcWorld);
|
||||
importer.importWorldAsyncStart(worldPath, 10, null, ()->{
|
||||
System.err.println("DONE IMPORT");
|
||||
});
|
||||
return importer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ 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.util.Mesher2Dv2;
|
||||
import me.cortex.voxelmon.core.world.WorldEngine;
|
||||
import me.cortex.voxelmon.core.world.WorldSection;
|
||||
import me.cortex.voxelmon.core.world.other.Mapper;
|
||||
@@ -11,7 +12,7 @@ import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
|
||||
public class RenderDataFactory {
|
||||
private final Mesher2D mesher = new Mesher2D(5,15);//15
|
||||
private final Mesher2Dv2 mesher = new Mesher2Dv2(5,15);//15
|
||||
private final LongArrayList outData = new LongArrayList(1000);
|
||||
private final WorldEngine world;
|
||||
public RenderDataFactory(WorldEngine world) {
|
||||
|
||||
175
src/main/java/me/cortex/voxelmon/core/util/Mesher2Dv2.java
Normal file
175
src/main/java/me/cortex/voxelmon/core/util/Mesher2Dv2.java
Normal file
@@ -0,0 +1,175 @@
|
||||
package me.cortex.voxelmon.core.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.Random;
|
||||
|
||||
public class Mesher2Dv2 {
|
||||
private final int size;
|
||||
private final int maxSize;
|
||||
private final long[] data;
|
||||
private final BitSet setset;
|
||||
private int[] quadCache;
|
||||
public Mesher2Dv2(int sizeBits, int maxSize) {
|
||||
this.size = sizeBits;
|
||||
this.maxSize = maxSize;
|
||||
this.data = new long[1<<(sizeBits<<1)];
|
||||
this.setset = new BitSet(1<<(sizeBits<<1));
|
||||
this.quadCache = new int[128];
|
||||
}
|
||||
|
||||
private int getIdx(int x, int z) {
|
||||
int M = (1<<this.size)-1;
|
||||
if (x>M || z>M) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return ((z&M)<<this.size)|(x&M);
|
||||
}
|
||||
|
||||
public Mesher2Dv2 put(int x, int z, long data) {
|
||||
int idx = this.getIdx(x, z);
|
||||
this.data[idx] = data;
|
||||
this.setset.set(idx);
|
||||
return this;
|
||||
}
|
||||
|
||||
public static int getX(int data) {
|
||||
return (data>>24)&0xFF;
|
||||
}
|
||||
|
||||
public static int getZ(int data) {
|
||||
return (data>>16)&0xFF;
|
||||
}
|
||||
|
||||
public static int getH(int data) {
|
||||
return (data>>8)&0xFF;
|
||||
}
|
||||
|
||||
public static int getW(int data) {
|
||||
return data&0xFF;
|
||||
}
|
||||
|
||||
//
|
||||
private static int encodeQuad(int x, int z, int sx, int sz) {
|
||||
return ((x&0xFF)<<24)|((z&0xFF)<<16)|((sx&0xFF)<<8)|((sz&0xFF)<<0);
|
||||
}
|
||||
|
||||
private boolean canMerge(int x, int z, long match) {
|
||||
int id = this.getIdx(x, z);
|
||||
return this.setset.get(id) && this.data[id] == match;
|
||||
}
|
||||
|
||||
public int[] process() {
|
||||
int[] quads = this.quadCache;
|
||||
int idxCount = 0;
|
||||
|
||||
//TODO: add different strategies/ways to mesh
|
||||
int posId = this.data[0] == 0?this.setset.nextSetBit(0):0;
|
||||
while (posId < this.data.length && posId != -1) {
|
||||
int idx = posId;
|
||||
long data = this.data[idx];
|
||||
|
||||
int M = (1<<this.size)-1;
|
||||
int x = idx&M;
|
||||
int z = (idx>>>this.size)&M;
|
||||
|
||||
boolean ex = x != ((1<<this.size)-1);
|
||||
boolean ez = z != ((1<<this.size)-1);
|
||||
int endX = x;
|
||||
int endZ = z;
|
||||
while (ex || ez) {
|
||||
//Expand in the x direction
|
||||
if (ex) {
|
||||
if (endX + 1 > this.maxSize || endX+1 == (1 << this.size) - 1) {
|
||||
ex = false;
|
||||
}
|
||||
}
|
||||
if (ex) {
|
||||
for (int tz = z; tz < endZ+1; tz++) {
|
||||
if (!this.canMerge(endX + 1, tz, data)) {
|
||||
ex = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ex) {
|
||||
endX++;
|
||||
}
|
||||
if (ez) {
|
||||
if (endZ + 1 > this.maxSize || endZ+1 == (1<<this.size)-1) {
|
||||
ez = false;
|
||||
}
|
||||
}
|
||||
if (ez) {
|
||||
for (int tx = x; tx < endX+1; tx++) {
|
||||
if (!this.canMerge(tx, endZ + 1, data)) {
|
||||
ez = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ez) {
|
||||
endZ++;
|
||||
}
|
||||
}
|
||||
|
||||
//Mark the sections as meshed
|
||||
for (int mx = x; mx <= endX; mx++) {
|
||||
for (int mz = z; mz <= endZ; mz++) {
|
||||
this.setset.clear(this.getIdx(mx, mz));
|
||||
}
|
||||
}
|
||||
|
||||
int encodedQuad = encodeQuad(x, z, endX - x + 1, endZ - z + 1);
|
||||
|
||||
{
|
||||
int pIdx = idxCount++;
|
||||
if (pIdx == quads.length) {
|
||||
var newArray = new int[quads.length + 64];
|
||||
System.arraycopy(quads, 0, newArray, 0, quads.length);
|
||||
quads = newArray;
|
||||
}
|
||||
quads[pIdx] = encodedQuad;
|
||||
}
|
||||
|
||||
|
||||
posId = this.setset.nextSetBit(posId);
|
||||
}
|
||||
|
||||
var out = new int[idxCount];
|
||||
System.arraycopy(quads, 0, out, 0, idxCount);
|
||||
this.quadCache = quads;
|
||||
return out;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
var r = new Random(123451);
|
||||
int a = 0;
|
||||
long total = 0;
|
||||
for (int i = 0; i < 200000; i++) {
|
||||
var mesh = new Mesher2Dv2(5,16);
|
||||
for (int j = 0; j < 512; j++) {
|
||||
mesh.put(r.nextInt(32), r.nextInt(32), r.nextInt(100));
|
||||
}
|
||||
long s = System.nanoTime();
|
||||
var result = mesh.process();
|
||||
total += System.nanoTime() - s;
|
||||
a += result.hashCode();
|
||||
}
|
||||
System.out.println(total/(1e+6));
|
||||
System.out.println((double) (total/(1e+6))/200000);
|
||||
//mesh.put(0,0,1);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.setset.clear();
|
||||
Arrays.fill(this.data, 0);
|
||||
}
|
||||
|
||||
public long getDataFromQuad(int quad) {
|
||||
return this.getData(getX(quad), getZ(quad));
|
||||
}
|
||||
|
||||
public long getData(int x, int z) {
|
||||
return this.data[this.getIdx(x, z)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
package me.cortex.voxelmon.importers;
|
||||
|
||||
import me.cortex.voxelmon.core.world.WorldEngine;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.World;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
public class BobbyImporter {
|
||||
private final WorldEngine world;
|
||||
private final World mcWorld;
|
||||
public BobbyImporter(WorldEngine worldEngine, World mcWorld) {
|
||||
this.world = worldEngine;
|
||||
this.mcWorld = mcWorld;
|
||||
}
|
||||
|
||||
//TODO: make the importer run in another thread with a progress callback
|
||||
public void importBobby(Path directory) {
|
||||
directory.forEach(child->{
|
||||
var file = child.toFile();
|
||||
if (!file.isFile()) {
|
||||
return;
|
||||
}
|
||||
var name = file.getName();
|
||||
var sections = name.split("\\.");
|
||||
if (sections.length != 4 || (!sections[0].equals("r")) || (!sections[3].equals("mca"))) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
int rx = Integer.parseInt(sections[1]);
|
||||
int rz = Integer.parseInt(sections[2]);
|
||||
});
|
||||
}
|
||||
|
||||
private void importRegionFile(Path file, int x, int z) throws IOException {
|
||||
try (var fileStream = FileChannel.open(file, StandardOpenOption.READ)) {
|
||||
var sectorsSavesBB = MemoryUtil.memAlloc(8192);
|
||||
if (fileStream.read(sectorsSavesBB) != 8192) {
|
||||
throw new IllegalStateException("Header of region file invalid");
|
||||
}
|
||||
var sectorsSaves = sectorsSavesBB.asIntBuffer();
|
||||
|
||||
//Find and load all saved chunks
|
||||
for (int idx = 0; idx < 1024; idx++) {
|
||||
int sectorMeta = sectorsSaves.get(idx);
|
||||
if (sectorMeta == 0) {
|
||||
//Empty chunk
|
||||
continue;
|
||||
}
|
||||
int sectorStart = sectorMeta>>>8;
|
||||
int sectorCount = sectorMeta&((1<<8)-1);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void importChunkNBT(ChunkPos pos, NbtCompound chunk) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,14 @@ import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class WorldImporter {
|
||||
public record ImportUpdate(){}
|
||||
|
||||
private final WorldEngine world;
|
||||
private final World mcWorld;
|
||||
private final Codec<ReadableContainer<RegistryEntry<Biome>>> biomeCodec;
|
||||
@@ -45,27 +51,35 @@ public class WorldImporter {
|
||||
}
|
||||
|
||||
private Thread worker;
|
||||
public void importWorldAsyncStart(File directory) {
|
||||
public void importWorldAsyncStart(File directory, int threads, Function<ImportUpdate, Boolean> updateCallback, Runnable onCompletion) {
|
||||
this.worker = new Thread(() -> {
|
||||
Arrays.stream(directory.listFiles()).parallel().forEach(file -> {
|
||||
var workers = new ForkJoinPool(threads);
|
||||
for (var file : directory.listFiles()) {
|
||||
if (!file.isFile()) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
var name = file.getName();
|
||||
var sections = name.split("\\.");
|
||||
if (sections.length != 4 || (!sections[0].equals("r")) || (!sections[3].equals("mca"))) {
|
||||
System.err.println("Unknown file: " + name);
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
int rx = Integer.parseInt(sections[1]);
|
||||
int rz = Integer.parseInt(sections[2]);
|
||||
try {
|
||||
this.importRegionFile(file.toPath(), rx, rz);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
System.err.println("Done");
|
||||
workers.submit(() -> {
|
||||
try {
|
||||
this.importRegionFile(file.toPath(), rx, rz);
|
||||
} catch (
|
||||
Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
workers.shutdown();
|
||||
try {
|
||||
workers.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
|
||||
} catch (InterruptedException e) {}
|
||||
onCompletion.run();
|
||||
});
|
||||
this.worker.setName("World importer");
|
||||
this.worker.start();
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package me.cortex.voxelmon.terrain;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import me.cortex.voxelmon.core.VoxelCore;
|
||||
import me.cortex.voxelmon.importers.WorldImporter;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientCommandSource;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
|
||||
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
|
||||
import static com.mojang.brigadier.builder.RequiredArgumentBuilder.argument;
|
||||
|
||||
|
||||
/*
|
||||
public class WorldImportCommand {
|
||||
public static void register(CommandDispatcher<ClientCommandSource> dispatcher) {
|
||||
dispatcher.register(literal("zenith")
|
||||
.then(literal("import").then(literal("world").then(argument("world_name", StringArgumentType.string()).executes(WorldImportCommand::importWorld)))));
|
||||
}
|
||||
|
||||
|
||||
private static int importWorld(CommandContext<ClientCommandSource> ctx) {
|
||||
VoxelCore.INSTANCE.createWorldImporter(MinecraftClient.getInstance().world, ctx.getArgument("world_name", String.class));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user