aaa
This commit is contained in:
@@ -5,21 +5,15 @@ import me.cortex.voxy.client.saver.ContextSelectionSystem;
|
|||||||
import me.cortex.voxy.client.terrain.WorldImportCommand;
|
import me.cortex.voxy.client.terrain.WorldImportCommand;
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientWorldEvents;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
|
|
||||||
public class Voxy implements ClientModInitializer {
|
public class VoxyClient implements ClientModInitializer {
|
||||||
@Override
|
@Override
|
||||||
public void onInitializeClient() {
|
public void onInitializeClient() {
|
||||||
|
/*
|
||||||
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
|
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
|
||||||
dispatcher.register(WorldImportCommand.register());
|
dispatcher.register(WorldImportCommand.register());
|
||||||
});
|
});*/
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static final ContextSelectionSystem SELECTOR = new ContextSelectionSystem();
|
|
||||||
|
|
||||||
public static VoxelCore createVoxelCore(ClientWorld world) {
|
|
||||||
var selection = SELECTOR.getBestSelectionOrCreate(world);
|
|
||||||
return new VoxelCore(selection);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,6 +21,7 @@ public class VoxyConfig {
|
|||||||
public static VoxyConfig CONFIG = loadOrCreate();
|
public static VoxyConfig CONFIG = loadOrCreate();
|
||||||
|
|
||||||
public boolean enabled = true;
|
public boolean enabled = true;
|
||||||
|
public boolean enableRendering = true;
|
||||||
public boolean ingestEnabled = true;
|
public boolean ingestEnabled = true;
|
||||||
//public int renderDistance = 128;
|
//public int renderDistance = 128;
|
||||||
public int serviceThreads = Math.max(Runtime.getRuntime().availableProcessors()/2, 1);
|
public int serviceThreads = Math.max(Runtime.getRuntime().availableProcessors()/2, 1);
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ package me.cortex.voxy.client.config;
|
|||||||
|
|
||||||
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
||||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||||
import me.cortex.voxy.client.core.IGetVoxelCore;
|
import me.cortex.voxy.client.core.IGetVoxyRenderSystem;
|
||||||
|
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||||
import me.shedaniel.clothconfig2.api.ConfigBuilder;
|
import me.shedaniel.clothconfig2.api.ConfigBuilder;
|
||||||
import me.shedaniel.clothconfig2.api.ConfigCategory;
|
import me.shedaniel.clothconfig2.api.ConfigCategory;
|
||||||
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
|
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
|
||||||
@@ -35,9 +36,13 @@ public class VoxyConfigScreenFactory implements ModMenuApi {
|
|||||||
|
|
||||||
builder.setSavingRunnable(() -> {
|
builder.setSavingRunnable(() -> {
|
||||||
//After saving the core should be reloaded/reset
|
//After saving the core should be reloaded/reset
|
||||||
var world = (IGetVoxelCore)MinecraftClient.getInstance().worldRenderer;
|
var world = MinecraftClient.getInstance().worldRenderer;
|
||||||
if (world != null && ON_SAVE_RELOAD) {
|
if (world != null && ON_SAVE_RELOAD) {
|
||||||
world.reloadVoxelCore();
|
//Reload voxy
|
||||||
|
((IGetVoxyRenderSystem)world).shutdownRenderer();
|
||||||
|
VoxyCommon.shutdownInstance();
|
||||||
|
VoxyCommon.createInstance();
|
||||||
|
((IGetVoxyRenderSystem)world).createRenderer();
|
||||||
}
|
}
|
||||||
ON_SAVE_RELOAD = false;
|
ON_SAVE_RELOAD = false;
|
||||||
VoxyConfig.CONFIG.save();
|
VoxyConfig.CONFIG.save();
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
package me.cortex.voxy.client.core;
|
|
||||||
|
|
||||||
import me.cortex.voxy.client.core.VoxelCore;
|
|
||||||
|
|
||||||
public interface IGetVoxelCore {
|
|
||||||
VoxelCore getVoxelCore();
|
|
||||||
|
|
||||||
void reloadVoxelCore();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package me.cortex.voxy.client.core;
|
||||||
|
|
||||||
|
import me.cortex.voxy.client.core.rendering.VoxyRenderSystem;
|
||||||
|
|
||||||
|
public interface IGetVoxyRenderSystem {
|
||||||
|
VoxyRenderSystem getVoxyRenderSystem();
|
||||||
|
void shutdownRenderer();
|
||||||
|
void createRenderer();
|
||||||
|
}
|
||||||
@@ -66,29 +66,18 @@ import static org.lwjgl.opengl.GL30C.*;
|
|||||||
//REMOVE setRenderGen like holy hell
|
//REMOVE setRenderGen like holy hell
|
||||||
public class VoxelCore {
|
public class VoxelCore {
|
||||||
private final WorldEngine world;
|
private final WorldEngine world;
|
||||||
|
public final ServiceThreadPool serviceThreadPool;
|
||||||
private final RenderService renderer;
|
|
||||||
private final PostProcessing postProcessing;
|
|
||||||
private final ServiceThreadPool serviceThreadPool;
|
|
||||||
|
|
||||||
public final WorldImportWrapper importer;
|
public final WorldImportWrapper importer;
|
||||||
|
|
||||||
public VoxelCore(ContextSelectionSystem.Selection worldSelection) {
|
public VoxelCore(ContextSelectionSystem.Selection worldSelection) {
|
||||||
var cfg = worldSelection.getConfig();
|
var cfg = worldSelection.getConfig();
|
||||||
this.serviceThreadPool = new ServiceThreadPool(VoxyConfig.CONFIG.serviceThreads);
|
this.serviceThreadPool = new ServiceThreadPool(VoxyConfig.CONFIG.serviceThreads);
|
||||||
|
|
||||||
this.world = worldSelection.createEngine(this.serviceThreadPool);
|
this.world = null;//worldSelection.createEngine(this.serviceThreadPool);
|
||||||
Logger.info("Initializing voxy core");
|
Logger.info("Initializing voxy core");
|
||||||
|
|
||||||
this.importer = new WorldImportWrapper(this.serviceThreadPool, this.world);
|
this.importer = new WorldImportWrapper(this.serviceThreadPool, this.world);
|
||||||
|
|
||||||
//Trigger the shared index buffer loading
|
|
||||||
SharedIndexBuffer.INSTANCE.id();
|
|
||||||
Capabilities.init();//Ensure clinit is called
|
|
||||||
|
|
||||||
this.renderer = new RenderService(this.world, this.serviceThreadPool);
|
|
||||||
this.postProcessing = new PostProcessing();
|
|
||||||
|
|
||||||
Logger.info("Voxy core initialized");
|
Logger.info("Voxy core initialized");
|
||||||
|
|
||||||
//this.verifyTopNodeChildren(0,0,0);
|
//this.verifyTopNodeChildren(0,0,0);
|
||||||
@@ -99,130 +88,16 @@ public class VoxelCore {
|
|||||||
//this.testFullMesh();
|
//this.testFullMesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enqueueIngest(WorldChunk worldChunk) {
|
|
||||||
this.world.ingestService.enqueueIngest(worldChunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void renderSetup(Frustum frustum, Camera camera) {
|
|
||||||
this.renderer.setup(camera);
|
|
||||||
PrintfDebugUtil.tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Matrix4f makeProjectionMatrix(float near, float far) {
|
|
||||||
//TODO: use the existing projection matrix use mulLocal by the inverse of the projection and then mulLocal our projection
|
|
||||||
|
|
||||||
var projection = new Matrix4f();
|
|
||||||
var client = MinecraftClient.getInstance();
|
|
||||||
var gameRenderer = client.gameRenderer;//tickCounter.getTickDelta(true);
|
|
||||||
|
|
||||||
float fov = gameRenderer.getFov(gameRenderer.getCamera(), client.getRenderTickCounter().getTickDelta(true), true);
|
|
||||||
|
|
||||||
projection.setPerspective(fov * 0.01745329238474369f,
|
|
||||||
(float) client.getWindow().getFramebufferWidth() / (float)client.getWindow().getFramebufferHeight(),
|
|
||||||
near, far);
|
|
||||||
return projection;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Make a reverse z buffer
|
|
||||||
private static Matrix4f computeProjectionMat() {
|
|
||||||
return new Matrix4f(RenderSystem.getProjectionMatrix()).mulLocal(
|
|
||||||
makeProjectionMatrix(0.05f, MinecraftClient.getInstance().gameRenderer.getFarPlaneDistance()).invert()
|
|
||||||
).mulLocal(makeProjectionMatrix(16, 16*3000));
|
|
||||||
}
|
|
||||||
|
|
||||||
//private static final ModelTextureBakery mtb = new ModelTextureBakery(16, 16);
|
|
||||||
//private static final RawDownloadStream downstream = new RawDownloadStream(1<<20);
|
|
||||||
public void renderOpaque(MatrixStack matrices, double cameraX, double cameraY, double cameraZ) {
|
|
||||||
/*
|
|
||||||
int allocation = downstream.download(2*4*6*16*16, ptr->{
|
|
||||||
});
|
|
||||||
mtb.renderFacesToStream(Blocks.WHITE_STAINED_GLASS.getDefaultState(), 123456, false, downstream.getBufferId(), allocation);
|
|
||||||
downstream.submit();
|
|
||||||
downstream.tick();
|
|
||||||
*/
|
|
||||||
//if (true) return;
|
|
||||||
|
|
||||||
|
|
||||||
if (IrisUtil.irisShadowActive()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false) {
|
|
||||||
float CHANGE_PER_SECOND = 30;
|
|
||||||
//Auto fps targeting
|
|
||||||
if (MinecraftClient.getInstance().getCurrentFps() < 45) {
|
|
||||||
VoxyConfig.CONFIG.subDivisionSize = Math.min(VoxyConfig.CONFIG.subDivisionSize + CHANGE_PER_SECOND / Math.max(1f, MinecraftClient.getInstance().getCurrentFps()), 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (55 < MinecraftClient.getInstance().getCurrentFps()) {
|
|
||||||
VoxyConfig.CONFIG.subDivisionSize = Math.max(VoxyConfig.CONFIG.subDivisionSize - CHANGE_PER_SECOND / Math.max(1f, MinecraftClient.getInstance().getCurrentFps()), 30);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Do some very cheeky stuff for MiB
|
|
||||||
if (false) {
|
|
||||||
int sector = (((int)Math.floor(cameraX)>>4)+512)>>10;
|
|
||||||
cameraX -= sector<<14;//10+4
|
|
||||||
cameraY += (16+(256-32-sector*30))*16;
|
|
||||||
}
|
|
||||||
|
|
||||||
matrices.push();
|
|
||||||
matrices.translate(-cameraX, -cameraY, -cameraZ);
|
|
||||||
matrices.pop();
|
|
||||||
|
|
||||||
var projection = computeProjectionMat();//RenderSystem.getProjectionMatrix();
|
|
||||||
//var projection = RenderSystem.getProjectionMatrix();
|
|
||||||
|
|
||||||
var viewport = this.renderer.getViewport();
|
|
||||||
viewport
|
|
||||||
.setProjection(projection)
|
|
||||||
.setModelView(matrices.peek().getPositionMatrix())
|
|
||||||
.setCamera(cameraX, cameraY, cameraZ)
|
|
||||||
.setScreenSize(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight);
|
|
||||||
viewport.frameId++;
|
|
||||||
|
|
||||||
int boundFB = GL11.glGetInteger(GL_DRAW_FRAMEBUFFER_BINDING);
|
|
||||||
if (boundFB == 0) {
|
|
||||||
throw new IllegalStateException("Cannot use the default framebuffer as cannot source from it");
|
|
||||||
}
|
|
||||||
//TODO: use the raw depth buffer texture instead
|
|
||||||
//int boundDepthBuffer = glGetNamedFramebufferAttachmentParameteri(boundFB, GL_DEPTH_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
|
||||||
|
|
||||||
//TODO:FIXME!!! ??
|
|
||||||
this.postProcessing.setup(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight, boundFB);
|
|
||||||
|
|
||||||
this.renderer.renderFarAwayOpaque(viewport);
|
|
||||||
|
|
||||||
//Compute the SSAO of the rendered terrain, TODO: fix it breaking depth or breaking _something_ am not sure what
|
|
||||||
this.postProcessing.computeSSAO(projection, matrices);
|
|
||||||
|
|
||||||
//We can render the translucent directly after as it is the furthest translucent objects
|
|
||||||
this.renderer.renderFarAwayTranslucent(viewport);
|
|
||||||
|
|
||||||
|
|
||||||
this.postProcessing.renderPost(projection, RenderSystem.getProjectionMatrix(), boundFB);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addDebugInfo(List<String> debug) {
|
public void addDebugInfo(List<String> debug) {
|
||||||
debug.add("");
|
debug.add("");
|
||||||
debug.add("");
|
debug.add("");
|
||||||
debug.add("Voxy Core: " + VoxyCommon.MOD_VERSION);
|
|
||||||
debug.add("MemoryBuffer, Count/Size (mb): " + MemoryBuffer.getCount() + "/" + (MemoryBuffer.getTotalSize()/1_000_000));
|
|
||||||
debug.add("GlBuffer, Count/Size (mb): " + GlBuffer.getCount() + "/" + (GlBuffer.getTotalSize()/1_000_000));
|
|
||||||
/*
|
/*
|
||||||
debug.add("Ingest service tasks: " + this.world.ingestService.getTaskCount());
|
debug.add("Ingest service tasks: " + this.world.ingestService.getTaskCount());
|
||||||
debug.add("Saving service tasks: " + this.world.savingService.getTaskCount());
|
debug.add("Saving service tasks: " + this.world.savingService.getTaskCount());
|
||||||
debug.add("Render service tasks: " + this.renderGen.getTaskCount());
|
debug.add("Render service tasks: " + this.renderGen.getTaskCount());
|
||||||
*/
|
*/
|
||||||
debug.add("I/S tasks: " + this.world.ingestService.getTaskCount() + "/"+this.world.savingService.getTaskCount());
|
|
||||||
this.world.addDebugData(debug);
|
this.world.addDebugData(debug);
|
||||||
this.renderer.addDebugData(debug);
|
|
||||||
|
|
||||||
PrintfDebugUtil.addToOut(debug);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Note: when doing translucent rendering, only need to sort when generating the geometry, or when crossing into the center zone
|
//Note: when doing translucent rendering, only need to sort when generating the geometry, or when crossing into the center zone
|
||||||
@@ -230,8 +105,6 @@ public class VoxelCore {
|
|||||||
// since they are AABBS crossing the normal is impossible without one of the axis being equal
|
// since they are AABBS crossing the normal is impossible without one of the axis being equal
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
Logger.info("Flushing download stream");
|
|
||||||
DownloadStream.INSTANCE.flushWaitClear();
|
|
||||||
|
|
||||||
//if (Thread.currentThread() != this.shutdownThread) {
|
//if (Thread.currentThread() != this.shutdownThread) {
|
||||||
// Runtime.getRuntime().removeShutdownHook(this.shutdownThread);
|
// Runtime.getRuntime().removeShutdownHook(this.shutdownThread);
|
||||||
@@ -239,10 +112,6 @@ public class VoxelCore {
|
|||||||
|
|
||||||
//this.world.getMapper().forceResaveStates();
|
//this.world.getMapper().forceResaveStates();
|
||||||
this.importer.shutdown();
|
this.importer.shutdown();
|
||||||
Logger.info("Shutting down rendering");
|
|
||||||
try {this.renderer.shutdown();} catch (Exception e) {Logger.error("Error shutting down renderer", e);}
|
|
||||||
Logger.info("Shutting down post processor");
|
|
||||||
if (this.postProcessing!=null){try {this.postProcessing.shutdown();} catch (Exception e) {Logger.error("Error shutting down post processor", e);}}
|
|
||||||
Logger.info("Shutting down world engine");
|
Logger.info("Shutting down world engine");
|
||||||
try {this.world.shutdown();} catch (Exception e) {Logger.error("Error shutting down world engine", e);}
|
try {this.world.shutdown();} catch (Exception e) {Logger.error("Error shutting down world engine", e);}
|
||||||
Logger.info("Shutting down service thread pool");
|
Logger.info("Shutting down service thread pool");
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import me.cortex.voxy.client.taskbar.Taskbar;
|
|||||||
import me.cortex.voxy.common.Logger;
|
import me.cortex.voxy.common.Logger;
|
||||||
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
||||||
import me.cortex.voxy.common.world.WorldEngine;
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
|
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||||
import me.cortex.voxy.commonImpl.importers.WorldImporter;
|
import me.cortex.voxy.commonImpl.importers.WorldImporter;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.gui.hud.ClientBossBar;
|
import net.minecraft.client.gui.hud.ClientBossBar;
|
||||||
@@ -28,7 +29,6 @@ public class WorldImportWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
|
|
||||||
Logger.info("Shutting down importer");
|
Logger.info("Shutting down importer");
|
||||||
if (this.importer != null) {
|
if (this.importer != null) {
|
||||||
try {
|
try {
|
||||||
@@ -58,7 +58,7 @@ public class WorldImportWrapper {
|
|||||||
}
|
}
|
||||||
public boolean createWorldImporter(World mcWorld, IImporterFactory factory) {
|
public boolean createWorldImporter(World mcWorld, IImporterFactory factory) {
|
||||||
if (this.importer == null) {
|
if (this.importer == null) {
|
||||||
this.importer = new WorldImporter(this.world, mcWorld, this.pool);
|
this.importer = new WorldImporter(this.world, mcWorld, this.pool, VoxyCommon.getInstance().getSavingService());
|
||||||
}
|
}
|
||||||
if (this.importer.isBusy()) {
|
if (this.importer.isBusy()) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -6,9 +6,6 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
|||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||||
import me.cortex.voxy.client.core.IGetVoxelCore;
|
|
||||||
import me.cortex.voxy.client.core.gl.GlBuffer;
|
|
||||||
import me.cortex.voxy.client.core.gl.GlTexture;
|
|
||||||
import me.cortex.voxy.client.core.rendering.util.RawDownloadStream;
|
import me.cortex.voxy.client.core.rendering.util.RawDownloadStream;
|
||||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
import me.cortex.voxy.common.Logger;
|
import me.cortex.voxy.common.Logger;
|
||||||
@@ -40,13 +37,8 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
import static me.cortex.voxy.client.core.model.ModelStore.MODEL_SIZE;
|
import static me.cortex.voxy.client.core.model.ModelStore.MODEL_SIZE;
|
||||||
import static org.lwjgl.opengl.GL11.*;
|
import static org.lwjgl.opengl.GL11.*;
|
||||||
import static org.lwjgl.opengl.GL11C.GL_NEAREST;
|
|
||||||
import static org.lwjgl.opengl.GL11C.GL_NEAREST_MIPMAP_LINEAR;
|
|
||||||
import static org.lwjgl.opengl.GL12C.GL_TEXTURE_MAX_LOD;
|
|
||||||
import static org.lwjgl.opengl.GL12C.GL_TEXTURE_MIN_LOD;
|
|
||||||
import static org.lwjgl.opengl.GL33.glDeleteSamplers;
|
import static org.lwjgl.opengl.GL33.glDeleteSamplers;
|
||||||
import static org.lwjgl.opengl.GL33.glGenSamplers;
|
import static org.lwjgl.opengl.GL33.glGenSamplers;
|
||||||
import static org.lwjgl.opengl.GL33C.glSamplerParameteri;
|
|
||||||
import static org.lwjgl.opengl.GL45C.glTextureSubImage2D;
|
import static org.lwjgl.opengl.GL45C.glTextureSubImage2D;
|
||||||
|
|
||||||
//Manages the storage and updating of model states, textures and colours
|
//Manages the storage and updating of model states, textures and colours
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package me.cortex.voxy.client.core.rendering;
|
package me.cortex.voxy.client.core.rendering;
|
||||||
|
|
||||||
import me.cortex.voxy.client.Voxy;
|
|
||||||
import me.cortex.voxy.client.core.gl.shader.IShaderProcessor;
|
import me.cortex.voxy.client.core.gl.shader.IShaderProcessor;
|
||||||
import me.cortex.voxy.client.core.gl.shader.PrintfInjector;
|
import me.cortex.voxy.client.core.gl.shader.PrintfInjector;
|
||||||
import me.cortex.voxy.client.core.gl.shader.ShaderType;
|
import me.cortex.voxy.client.core.gl.shader.ShaderType;
|
||||||
|
|||||||
@@ -44,7 +44,10 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
|
|||||||
private final MessageQueue<WorldSection> sectionUpdateQueue;
|
private final MessageQueue<WorldSection> sectionUpdateQueue;
|
||||||
private final MessageQueue<BuiltSection> geometryUpdateQueue;
|
private final MessageQueue<BuiltSection> geometryUpdateQueue;
|
||||||
|
|
||||||
|
private final WorldEngine world;
|
||||||
|
|
||||||
public RenderService(WorldEngine world, ServiceThreadPool serviceThreadPool) {
|
public RenderService(WorldEngine world, ServiceThreadPool serviceThreadPool) {
|
||||||
|
this.world = world;
|
||||||
this.modelService = new ModelBakerySubsystem(world.getMapper());
|
this.modelService = new ModelBakerySubsystem(world.getMapper());
|
||||||
|
|
||||||
//Max sections: ~500k
|
//Max sections: ~500k
|
||||||
@@ -224,6 +227,11 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
|
//Cleanup callbacks
|
||||||
|
this.world.setDirtyCallback(null);
|
||||||
|
this.world.getMapper().setBiomeCallback(null);
|
||||||
|
this.world.getMapper().setStateCallback(null);
|
||||||
|
|
||||||
this.modelService.shutdown();
|
this.modelService.shutdown();
|
||||||
this.renderGen.shutdown();
|
this.renderGen.shutdown();
|
||||||
this.viewportSelector.free();
|
this.viewportSelector.free();
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
package me.cortex.voxy.client.core.rendering;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import me.cortex.voxy.client.config.VoxyConfig;
|
||||||
|
import me.cortex.voxy.client.core.gl.Capabilities;
|
||||||
|
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||||
|
import me.cortex.voxy.client.core.rendering.post.PostProcessing;
|
||||||
|
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
|
||||||
|
import me.cortex.voxy.client.core.util.IrisUtil;
|
||||||
|
import me.cortex.voxy.common.Logger;
|
||||||
|
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
||||||
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.render.Camera;
|
||||||
|
import net.minecraft.client.render.Frustum;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL30C.GL_DRAW_FRAMEBUFFER_BINDING;
|
||||||
|
|
||||||
|
public class VoxyRenderSystem {
|
||||||
|
private final RenderService renderer;
|
||||||
|
private final PostProcessing postProcessing;
|
||||||
|
|
||||||
|
public VoxyRenderSystem(WorldEngine world, ServiceThreadPool threadPool) {
|
||||||
|
//Trigger the shared index buffer loading
|
||||||
|
SharedIndexBuffer.INSTANCE.id();
|
||||||
|
Capabilities.init();//Ensure clinit is called
|
||||||
|
|
||||||
|
this.renderer = new RenderService(world, threadPool);
|
||||||
|
this.postProcessing = new PostProcessing();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void renderSetup(Frustum frustum, Camera camera) {
|
||||||
|
this.renderer.setup(camera);
|
||||||
|
PrintfDebugUtil.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Matrix4f makeProjectionMatrix(float near, float far) {
|
||||||
|
//TODO: use the existing projection matrix use mulLocal by the inverse of the projection and then mulLocal our projection
|
||||||
|
|
||||||
|
var projection = new Matrix4f();
|
||||||
|
var client = MinecraftClient.getInstance();
|
||||||
|
var gameRenderer = client.gameRenderer;//tickCounter.getTickDelta(true);
|
||||||
|
|
||||||
|
float fov = gameRenderer.getFov(gameRenderer.getCamera(), client.getRenderTickCounter().getTickDelta(true), true);
|
||||||
|
|
||||||
|
projection.setPerspective(fov * 0.01745329238474369f,
|
||||||
|
(float) client.getWindow().getFramebufferWidth() / (float)client.getWindow().getFramebufferHeight(),
|
||||||
|
near, far);
|
||||||
|
return projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Make a reverse z buffer
|
||||||
|
private static Matrix4f computeProjectionMat() {
|
||||||
|
return new Matrix4f(RenderSystem.getProjectionMatrix()).mulLocal(
|
||||||
|
makeProjectionMatrix(0.05f, MinecraftClient.getInstance().gameRenderer.getFarPlaneDistance()).invert()
|
||||||
|
).mulLocal(makeProjectionMatrix(16, 16*3000));
|
||||||
|
}
|
||||||
|
|
||||||
|
//private static final ModelTextureBakery mtb = new ModelTextureBakery(16, 16);
|
||||||
|
//private static final RawDownloadStream downstream = new RawDownloadStream(1<<20);
|
||||||
|
public void renderOpaque(MatrixStack matrices, double cameraX, double cameraY, double cameraZ) {
|
||||||
|
/*
|
||||||
|
int allocation = downstream.download(2*4*6*16*16, ptr->{
|
||||||
|
});
|
||||||
|
mtb.renderFacesToStream(Blocks.WHITE_STAINED_GLASS.getDefaultState(), 123456, false, downstream.getBufferId(), allocation);
|
||||||
|
downstream.submit();
|
||||||
|
downstream.tick();
|
||||||
|
*/
|
||||||
|
//if (true) return;
|
||||||
|
|
||||||
|
|
||||||
|
if (IrisUtil.irisShadowActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false) {
|
||||||
|
float CHANGE_PER_SECOND = 30;
|
||||||
|
//Auto fps targeting
|
||||||
|
if (MinecraftClient.getInstance().getCurrentFps() < 45) {
|
||||||
|
VoxyConfig.CONFIG.subDivisionSize = Math.min(VoxyConfig.CONFIG.subDivisionSize + CHANGE_PER_SECOND / Math.max(1f, MinecraftClient.getInstance().getCurrentFps()), 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (55 < MinecraftClient.getInstance().getCurrentFps()) {
|
||||||
|
VoxyConfig.CONFIG.subDivisionSize = Math.max(VoxyConfig.CONFIG.subDivisionSize - CHANGE_PER_SECOND / Math.max(1f, MinecraftClient.getInstance().getCurrentFps()), 30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Do some very cheeky stuff for MiB
|
||||||
|
if (false) {
|
||||||
|
int sector = (((int)Math.floor(cameraX)>>4)+512)>>10;
|
||||||
|
cameraX -= sector<<14;//10+4
|
||||||
|
cameraY += (16+(256-32-sector*30))*16;
|
||||||
|
}
|
||||||
|
|
||||||
|
matrices.push();
|
||||||
|
matrices.translate(-cameraX, -cameraY, -cameraZ);
|
||||||
|
matrices.pop();
|
||||||
|
|
||||||
|
var projection = computeProjectionMat();//RenderSystem.getProjectionMatrix();
|
||||||
|
//var projection = RenderSystem.getProjectionMatrix();
|
||||||
|
|
||||||
|
var viewport = this.renderer.getViewport();
|
||||||
|
viewport
|
||||||
|
.setProjection(projection)
|
||||||
|
.setModelView(matrices.peek().getPositionMatrix())
|
||||||
|
.setCamera(cameraX, cameraY, cameraZ)
|
||||||
|
.setScreenSize(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight);
|
||||||
|
viewport.frameId++;
|
||||||
|
|
||||||
|
int boundFB = GL11.glGetInteger(GL_DRAW_FRAMEBUFFER_BINDING);
|
||||||
|
if (boundFB == 0) {
|
||||||
|
throw new IllegalStateException("Cannot use the default framebuffer as cannot source from it");
|
||||||
|
}
|
||||||
|
//TODO: use the raw depth buffer texture instead
|
||||||
|
//int boundDepthBuffer = glGetNamedFramebufferAttachmentParameteri(boundFB, GL_DEPTH_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||||
|
|
||||||
|
//TODO:FIXME!!! ??
|
||||||
|
this.postProcessing.setup(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight, boundFB);
|
||||||
|
|
||||||
|
this.renderer.renderFarAwayOpaque(viewport);
|
||||||
|
|
||||||
|
//Compute the SSAO of the rendered terrain, TODO: fix it breaking depth or breaking _something_ am not sure what
|
||||||
|
this.postProcessing.computeSSAO(projection, matrices);
|
||||||
|
|
||||||
|
//We can render the translucent directly after as it is the furthest translucent objects
|
||||||
|
this.renderer.renderFarAwayTranslucent(viewport);
|
||||||
|
|
||||||
|
|
||||||
|
this.postProcessing.renderPost(projection, RenderSystem.getProjectionMatrix(), boundFB);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDebugInfo(List<String> debug) {
|
||||||
|
debug.add("GlBuffer, Count/Size (mb): " + GlBuffer.getCount() + "/" + (GlBuffer.getTotalSize()/1_000_000));
|
||||||
|
this.renderer.addDebugData(debug);
|
||||||
|
PrintfDebugUtil.addToOut(debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
Logger.info("Flushing download stream");
|
||||||
|
DownloadStream.INSTANCE.flushWaitClear();
|
||||||
|
Logger.info("Shutting down rendering");
|
||||||
|
try {this.renderer.shutdown();} catch (Exception e) {Logger.error("Error shutting down renderer", e);}
|
||||||
|
Logger.info("Shutting down post processor");
|
||||||
|
if (this.postProcessing!=null){try {this.postProcessing.shutdown();} catch (Exception e) {Logger.error("Error shutting down post processor", e);}}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package me.cortex.voxy.client.mixin.minecraft;
|
package me.cortex.voxy.client.mixin.minecraft;
|
||||||
|
|
||||||
import me.cortex.voxy.client.core.IGetVoxelCore;
|
import me.cortex.voxy.client.core.IGetVoxyRenderSystem;
|
||||||
|
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.gui.hud.DebugHud;
|
import net.minecraft.client.gui.hud.DebugHud;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@@ -15,9 +16,15 @@ public class MixinDebugHud {
|
|||||||
@Inject(method = "getRightText", at = @At("TAIL"))
|
@Inject(method = "getRightText", at = @At("TAIL"))
|
||||||
private void injectDebug(CallbackInfoReturnable<List<String>> cir) {
|
private void injectDebug(CallbackInfoReturnable<List<String>> cir) {
|
||||||
var ret = cir.getReturnValue();
|
var ret = cir.getReturnValue();
|
||||||
var core = ((IGetVoxelCore) MinecraftClient.getInstance().worldRenderer).getVoxelCore();
|
var instance = VoxyCommon.getInstance();
|
||||||
if (core != null) {
|
if (instance != null) {
|
||||||
core.addDebugInfo(ret);
|
ret.add("");
|
||||||
|
ret.add("");
|
||||||
|
instance.addDebug(ret);
|
||||||
|
}
|
||||||
|
var renderer = ((IGetVoxyRenderSystem) MinecraftClient.getInstance().worldRenderer).getVoxyRenderSystem();
|
||||||
|
if (renderer != null) {
|
||||||
|
renderer.addDebugInfo(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package me.cortex.voxy.client.mixin.minecraft;
|
package me.cortex.voxy.client.mixin.minecraft;
|
||||||
|
|
||||||
|
import me.cortex.voxy.client.config.VoxyConfig;
|
||||||
|
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.RunArgs;
|
import net.minecraft.client.RunArgs;
|
||||||
|
import net.minecraft.client.gui.screen.DownloadingTerrainScreen;
|
||||||
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
@@ -13,4 +17,16 @@ public class MixinMinecraftClient {
|
|||||||
private void injectRenderDoc(RunArgs args, CallbackInfo ci) {
|
private void injectRenderDoc(RunArgs args, CallbackInfo ci) {
|
||||||
//System.load("C:\\Program Files\\RenderDoc\\renderdoc.dll");
|
//System.load("C:\\Program Files\\RenderDoc\\renderdoc.dll");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject(method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;Z)V", at = @At("TAIL"))
|
||||||
|
private void voxy$injectWorldClose(CallbackInfo ci) {
|
||||||
|
VoxyCommon.shutdownInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "joinWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;setWorld(Lnet/minecraft/client/world/ClientWorld;)V", shift = At.Shift.BEFORE))
|
||||||
|
private void voxy$injectInitialization(ClientWorld world, DownloadingTerrainScreen.WorldEntryReason worldEntryReason, CallbackInfo ci) {
|
||||||
|
if (VoxyConfig.CONFIG.enabled) {
|
||||||
|
VoxyCommon.createInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
package me.cortex.voxy.client.mixin.minecraft;
|
package me.cortex.voxy.client.mixin.minecraft;
|
||||||
|
|
||||||
import me.cortex.voxy.client.Voxy;
|
import me.cortex.voxy.client.VoxyClient;
|
||||||
import me.cortex.voxy.client.core.IGetVoxelCore;
|
|
||||||
import me.cortex.voxy.client.config.VoxyConfig;
|
import me.cortex.voxy.client.config.VoxyConfig;
|
||||||
import me.cortex.voxy.client.core.VoxelCore;
|
import me.cortex.voxy.client.core.IGetVoxyRenderSystem;
|
||||||
|
import me.cortex.voxy.client.core.rendering.VoxyRenderSystem;
|
||||||
|
import me.cortex.voxy.common.Logger;
|
||||||
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
|
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||||
|
import me.cortex.voxy.commonImpl.VoxyInstance;
|
||||||
import net.minecraft.client.render.*;
|
import net.minecraft.client.render.*;
|
||||||
import net.minecraft.client.util.ObjectAllocator;
|
import net.minecraft.client.util.ObjectAllocator;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
@@ -15,81 +18,71 @@ import org.spongepowered.asm.mixin.Shadow;
|
|||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
@Mixin(WorldRenderer.class)
|
@Mixin(WorldRenderer.class)
|
||||||
public abstract class MixinWorldRenderer implements IGetVoxelCore {
|
public abstract class MixinWorldRenderer implements IGetVoxyRenderSystem {
|
||||||
@Shadow private Frustum frustum;
|
@Shadow private Frustum frustum;
|
||||||
|
|
||||||
@Shadow private @Nullable ClientWorld world;
|
@Shadow private @Nullable ClientWorld world;
|
||||||
@Unique private VoxelCore core;
|
@Unique private VoxyRenderSystem renderer;
|
||||||
|
|
||||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;setupTerrain(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/Frustum;ZZ)V", shift = At.Shift.AFTER))
|
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;setupTerrain(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/Frustum;ZZ)V", shift = At.Shift.AFTER))
|
||||||
private void injectSetup(ObjectAllocator allocator, RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, Matrix4f positionMatrix, Matrix4f projectionMatrix, CallbackInfo ci) {
|
private void injectSetup(ObjectAllocator allocator, RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, Matrix4f positionMatrix, Matrix4f projectionMatrix, CallbackInfo ci) {
|
||||||
if (this.core != null) {
|
if (this.renderer != null) {
|
||||||
this.core.renderSetup(this.frustum, camera);
|
this.renderer.renderSetup(this.frustum, camera);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unique
|
@Override
|
||||||
public void populateCore() {
|
public VoxyRenderSystem getVoxyRenderSystem() {
|
||||||
if (this.core != null) {
|
return this.renderer;
|
||||||
throw new IllegalStateException("Trying to create new core while a core already exists");
|
|
||||||
}
|
|
||||||
this.core = Voxy.createVoxelCore(this.world);
|
|
||||||
}
|
|
||||||
|
|
||||||
public VoxelCore getVoxelCore() {
|
|
||||||
return this.core;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(method = "reload()V", at = @At("TAIL"))
|
@Inject(method = "reload()V", at = @At("TAIL"))
|
||||||
private void resetVoxelCore(CallbackInfo ci) {
|
private void reloadVoxyRenderer(CallbackInfo ci) {
|
||||||
if (this.world != null && this.core != null) {
|
this.shutdownRenderer();
|
||||||
this.core.shutdown();
|
if (this.world != null) {
|
||||||
this.core = null;
|
this.createRenderer();
|
||||||
if (VoxyConfig.CONFIG.enabled) {
|
|
||||||
this.populateCore();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(method = "setWorld", at = @At("TAIL"))
|
@Inject(method = "setWorld", at = @At("TAIL"))
|
||||||
private void initVoxelCore(ClientWorld world, CallbackInfo ci) {
|
private void initVoxelCore(ClientWorld world, CallbackInfo ci) {
|
||||||
if (world == null) {
|
if (world == null) {
|
||||||
if (this.core != null) {
|
this.shutdownRenderer();
|
||||||
this.core.shutdown();
|
|
||||||
this.core = null;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.core != null) {
|
|
||||||
this.core.shutdown();
|
|
||||||
this.core = null;
|
|
||||||
}
|
|
||||||
if (VoxyConfig.CONFIG.enabled) {
|
|
||||||
this.populateCore();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reloadVoxelCore() {
|
|
||||||
if (this.core != null) {
|
|
||||||
this.core.shutdown();
|
|
||||||
this.core = null;
|
|
||||||
}
|
|
||||||
if (this.world != null && VoxyConfig.CONFIG.enabled) {
|
|
||||||
this.populateCore();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(method = "close", at = @At("HEAD"))
|
@Inject(method = "close", at = @At("HEAD"))
|
||||||
private void injectClose(CallbackInfo ci) {
|
private void injectClose(CallbackInfo ci) {
|
||||||
if (this.core != null) {
|
this.shutdownRenderer();
|
||||||
this.core.shutdown();
|
|
||||||
this.core = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdownRenderer() {
|
||||||
|
if (this.renderer != null) {
|
||||||
|
this.renderer.shutdown();
|
||||||
|
this.renderer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createRenderer() {
|
||||||
|
if (this.renderer != null) throw new IllegalStateException("Cannot have multiple renderers");
|
||||||
|
if ((!VoxyConfig.CONFIG.enableRendering)||(!VoxyConfig.CONFIG.enabled)) {
|
||||||
|
Logger.info("Not creating renderer due to disabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var instance = VoxyCommon.getInstance();
|
||||||
|
if (instance == null) {
|
||||||
|
Logger.error("Not creating renderer due to null instance");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WorldEngine world = instance.getOrMakeWorld(this.world);
|
||||||
|
if (world == null) {
|
||||||
|
Logger.error("Null world selected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.renderer = new VoxyRenderSystem(world, instance.getThreadPool());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package me.cortex.voxy.client.mixin.sodium;
|
package me.cortex.voxy.client.mixin.sodium;
|
||||||
|
|
||||||
import me.cortex.voxy.client.core.IGetVoxelCore;
|
import me.cortex.voxy.client.core.IGetVoxyRenderSystem;
|
||||||
import me.cortex.voxy.client.core.util.IrisUtil;
|
|
||||||
import net.caffeinemc.mods.sodium.client.gl.device.CommandList;
|
import net.caffeinemc.mods.sodium.client.gl.device.CommandList;
|
||||||
import net.caffeinemc.mods.sodium.client.render.chunk.ChunkRenderMatrices;
|
import net.caffeinemc.mods.sodium.client.render.chunk.ChunkRenderMatrices;
|
||||||
import net.caffeinemc.mods.sodium.client.render.chunk.DefaultChunkRenderer;
|
import net.caffeinemc.mods.sodium.client.render.chunk.DefaultChunkRenderer;
|
||||||
@@ -9,13 +8,10 @@ import net.caffeinemc.mods.sodium.client.render.chunk.lists.ChunkRenderListItera
|
|||||||
import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses;
|
import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses;
|
||||||
import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass;
|
import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass;
|
||||||
import net.caffeinemc.mods.sodium.client.render.viewport.CameraTransform;
|
import net.caffeinemc.mods.sodium.client.render.viewport.CameraTransform;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
import org.spongepowered.asm.mixin.FabricUtil;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
@@ -26,12 +22,12 @@ public class MixinDefaultChunkRenderer {
|
|||||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/caffeinemc/mods/sodium/client/render/chunk/ShaderChunkRenderer;end(Lnet/caffeinemc/mods/sodium/client/render/chunk/terrain/TerrainRenderPass;)V", shift = At.Shift.BEFORE))
|
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/caffeinemc/mods/sodium/client/render/chunk/ShaderChunkRenderer;end(Lnet/caffeinemc/mods/sodium/client/render/chunk/terrain/TerrainRenderPass;)V", shift = At.Shift.BEFORE))
|
||||||
private void injectRender(ChunkRenderMatrices matrices, CommandList commandList, ChunkRenderListIterable renderLists, TerrainRenderPass renderPass, CameraTransform camera, CallbackInfo ci) {
|
private void injectRender(ChunkRenderMatrices matrices, CommandList commandList, ChunkRenderListIterable renderLists, TerrainRenderPass renderPass, CameraTransform camera, CallbackInfo ci) {
|
||||||
if (renderPass == DefaultTerrainRenderPasses.CUTOUT) {
|
if (renderPass == DefaultTerrainRenderPasses.CUTOUT) {
|
||||||
var core = ((IGetVoxelCore) MinecraftClient.getInstance().worldRenderer).getVoxelCore();
|
var renderer = ((IGetVoxyRenderSystem) MinecraftClient.getInstance().worldRenderer).getVoxyRenderSystem();
|
||||||
if (core != null) {
|
if (renderer != null) {
|
||||||
var stack = new MatrixStack();
|
var stack = new MatrixStack();
|
||||||
stack.loadIdentity();
|
stack.loadIdentity();
|
||||||
stack.multiplyPositionMatrix(new Matrix4f(matrices.modelView()));
|
stack.multiplyPositionMatrix(new Matrix4f(matrices.modelView()));
|
||||||
core.renderOpaque(stack, camera.x, camera.y, camera.z);
|
renderer.renderOpaque(stack, camera.x, camera.y, camera.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.cortex.voxy.client.mixin.sodium;
|
package me.cortex.voxy.client.mixin.sodium;
|
||||||
|
|
||||||
import me.cortex.voxy.client.config.VoxyConfig;
|
import me.cortex.voxy.client.config.VoxyConfig;
|
||||||
import me.cortex.voxy.client.core.IGetVoxelCore;
|
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||||
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager;
|
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
@@ -13,14 +13,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
|
|
||||||
@Mixin(value = RenderSectionManager.class, remap = false)
|
@Mixin(value = RenderSectionManager.class, remap = false)
|
||||||
public class MixinRenderSectionManager {
|
public class MixinRenderSectionManager {
|
||||||
|
|
||||||
@Shadow @Final private ClientWorld level;
|
@Shadow @Final private ClientWorld level;
|
||||||
|
|
||||||
@Inject(method = "onChunkRemoved", at = @At("HEAD"))
|
@Inject(method = "onChunkRemoved", at = @At("HEAD"))
|
||||||
private void injectIngest(int x, int z, CallbackInfo ci) {
|
private void injectIngest(int x, int z, CallbackInfo ci) {
|
||||||
var core = ((IGetVoxelCore)(this.level.worldRenderer)).getVoxelCore();
|
//TODO: Am not quite sure if this is right
|
||||||
if (core != null && VoxyConfig.CONFIG.ingestEnabled) {
|
var instance = VoxyCommon.getInstance();
|
||||||
core.enqueueIngest(this.level.getChunk(x, z));
|
if (instance != null && VoxyConfig.CONFIG.ingestEnabled) {
|
||||||
|
instance.getIngestService().enqueueIngest(this.level.getChunk(x, z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,10 +104,6 @@ public class ContextSelectionSystem {
|
|||||||
return this.config.sectionStorageConfig.build(ctx);
|
return this.config.sectionStorageConfig.build(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldEngine createEngine(ServiceThreadPool serviceThreadPool) {
|
|
||||||
return new WorldEngine(this.createSectionStorageBackend(), serviceThreadPool, VoxyConfig.CONFIG.secondaryLruCacheSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Saves the config for the world selection or something, need to figure out how to make it work with dimensional configs maybe?
|
//Saves the config for the world selection or something, need to figure out how to make it work with dimensional configs maybe?
|
||||||
// or just have per world config, cause when creating the world engine doing the string substitution would
|
// or just have per world config, cause when creating the world engine doing the string substitution would
|
||||||
// make it automatically select the right id
|
// make it automatically select the right id
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import com.mojang.brigadier.suggestion.Suggestions;
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||||
import me.cortex.voxy.client.core.IGetVoxelCore;
|
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||||
import me.cortex.voxy.client.core.VoxelCore;
|
import me.cortex.voxy.commonImpl.VoxyInstance;
|
||||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
|
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
|
||||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
@@ -20,8 +20,9 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
|
|
||||||
|
|
||||||
public class WorldImportCommand {
|
public class WorldImportCommand {
|
||||||
|
/*
|
||||||
public static LiteralArgumentBuilder<FabricClientCommandSource> register() {
|
public static LiteralArgumentBuilder<FabricClientCommandSource> register() {
|
||||||
return ClientCommandManager.literal("voxy").requires((ctx)-> ((IGetVoxelCore)MinecraftClient.getInstance().worldRenderer).getVoxelCore() != null)
|
return ClientCommandManager.literal("voxy").requires((ctx)-> VoxyCommon.getInstance() != null)
|
||||||
.then(ClientCommandManager.literal("import")
|
.then(ClientCommandManager.literal("import")
|
||||||
.then(ClientCommandManager.literal("world")
|
.then(ClientCommandManager.literal("world")
|
||||||
.then(ClientCommandManager.argument("world_name", StringArgumentType.string())
|
.then(ClientCommandManager.argument("world_name", StringArgumentType.string())
|
||||||
@@ -138,5 +139,5 @@ public class WorldImportCommand {
|
|||||||
String finalInnerDir = innerDir;
|
String finalInnerDir = innerDir;
|
||||||
return core.importer.createWorldImporter(instance.player.clientWorld,
|
return core.importer.createWorldImporter(instance.player.clientWorld,
|
||||||
(importer, up, done)->importer.importZippedRegionDirectoryAsyncStart(zip, finalInnerDir, up, done))?0:1;
|
(importer, up, done)->importer.importZippedRegionDirectoryAsyncStart(zip, finalInnerDir, up, done))?0:1;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package me.cortex.voxy.common;
|
package me.cortex.voxy.common;
|
||||||
|
|
||||||
|
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -16,7 +19,11 @@ public class Logger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var stackEntry = new Throwable().getStackTrace()[1];
|
var stackEntry = new Throwable().getStackTrace()[1];
|
||||||
LOGGER.error("["+stackEntry.getClassName()+"]: "+ Stream.of(args).map(Object::toString).collect(Collectors.joining(" ")), throwable);
|
String error = "["+stackEntry.getClassName()+"]: "+ Stream.of(args).map(Object::toString).collect(Collectors.joining(" "));
|
||||||
|
LOGGER.error(error, throwable);
|
||||||
|
if (!VoxyCommon.IS_DEDICATED_SERVER) {
|
||||||
|
MinecraftClient.getInstance().executeSync(()->{var player = MinecraftClient.getInstance().player; if (player != null) player.sendMessage(Text.literal(error), true);});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void warn(Object... args) {
|
public static void warn(Object... args) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.google.gson.*;
|
|||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import com.google.gson.stream.JsonReader;
|
import com.google.gson.stream.JsonReader;
|
||||||
import com.google.gson.stream.JsonWriter;
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import me.cortex.voxy.common.Logger;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@@ -132,20 +133,19 @@ public class Serialization {
|
|||||||
nameMethod.setAccessible(true);
|
nameMethod.setAccessible(true);
|
||||||
} catch (NoSuchMethodException e) {}
|
} catch (NoSuchMethodException e) {}
|
||||||
if (nameMethod == null) {
|
if (nameMethod == null) {
|
||||||
System.err.println("WARNING: Config class " + clzName + " doesnt contain a getConfigTypeName and thus wont be serializable");
|
Logger.error("WARNING: Config class " + clzName + " doesnt contain a getConfigTypeName and thus wont be serializable");
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
String name = (String) nameMethod.invoke(null);
|
String name = (String) nameMethod.invoke(null);
|
||||||
serializers.computeIfAbsent(clz, GsonConfigSerialization::new)
|
serializers.computeIfAbsent(clz, GsonConfigSerialization::new)
|
||||||
.register(name, (Class) original);
|
.register(name, (Class) original);
|
||||||
System.out.println("Registered " + original.getSimpleName() + " as " + name + " for config type " + clz.getSimpleName());
|
Logger.info("Registered " + original.getSimpleName() + " as " + name + " for config type " + clz.getSimpleName());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println("Error while setting up config serialization");
|
Logger.error("Error while setting up config serialization", e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ public class Serialization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GSON = builder.create();
|
GSON = builder.create();
|
||||||
System.out.println("Registered " + count + " config types");
|
Logger.info("Registered " + count + " config types");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> collectAllClasses(String pack) {
|
private static List<String> collectAllClasses(String pack) {
|
||||||
@@ -173,7 +173,7 @@ public class Serialization {
|
|||||||
}
|
}
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println("Failed to collect classes in package: " + pack);
|
Logger.error("Failed to collect classes in package: " + pack, e);
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,8 +191,7 @@ public class Serialization {
|
|||||||
return Stream.of();
|
return Stream.of();
|
||||||
}
|
}
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
} catch (
|
} catch (IOException e) {
|
||||||
IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public class ServiceSlice extends TrackedObject {
|
|||||||
//Tells the system that a single instance of this service needs executing
|
//Tells the system that a single instance of this service needs executing
|
||||||
public void execute() {
|
public void execute() {
|
||||||
if (!this.alive) {
|
if (!this.alive) {
|
||||||
System.err.println("Tried to do work on a dead service");
|
Logger.error("Tried to do work on a dead service: " + this.name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.jobCount.release();
|
this.jobCount.release();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
|||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
import me.cortex.voxy.common.util.VolatileHolder;
|
import me.cortex.voxy.common.util.VolatileHolder;
|
||||||
import me.cortex.voxy.common.world.other.Mapper;
|
import me.cortex.voxy.common.world.other.Mapper;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@@ -18,10 +19,18 @@ public class ActiveSectionTracker {
|
|||||||
private final SectionLoader loader;
|
private final SectionLoader loader;
|
||||||
|
|
||||||
private final int maxLRUSectionPerSlice;
|
private final int maxLRUSectionPerSlice;
|
||||||
private final Long2ObjectLinkedOpenHashMap<WorldSection>[] lruSecondaryCache;
|
private final Long2ObjectLinkedOpenHashMap<WorldSection>[] lruSecondaryCache;//TODO: THIS NEEDS TO BECOME A GLOBAL STATIC CACHE
|
||||||
|
@Nullable
|
||||||
|
public final WorldEngine engine;
|
||||||
|
|
||||||
|
public ActiveSectionTracker(int numSlicesBits, SectionLoader loader, int cacheSize) {
|
||||||
|
this(numSlicesBits, loader, cacheSize, null);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public ActiveSectionTracker(int numSlicesBits, SectionLoader loader, int cacheSize) {
|
public ActiveSectionTracker(int numSlicesBits, SectionLoader loader, int cacheSize, WorldEngine engine) {
|
||||||
|
this.engine = engine;
|
||||||
|
|
||||||
this.loader = loader;
|
this.loader = loader;
|
||||||
this.loadedSectionCache = new Long2ObjectOpenHashMap[1<<numSlicesBits];
|
this.loadedSectionCache = new Long2ObjectOpenHashMap[1<<numSlicesBits];
|
||||||
this.lruSecondaryCache = new Long2ObjectLinkedOpenHashMap[1<<numSlicesBits];
|
this.lruSecondaryCache = new Long2ObjectLinkedOpenHashMap[1<<numSlicesBits];
|
||||||
|
|||||||
@@ -2,18 +2,10 @@ package me.cortex.voxy.common.world;
|
|||||||
|
|
||||||
import me.cortex.voxy.common.Logger;
|
import me.cortex.voxy.common.Logger;
|
||||||
import me.cortex.voxy.common.config.section.SectionStorage;
|
import me.cortex.voxy.common.config.section.SectionStorage;
|
||||||
import me.cortex.voxy.common.util.ThreadLocalMemoryBuffer;
|
|
||||||
import me.cortex.voxy.common.voxelization.VoxelizedSection;
|
import me.cortex.voxy.common.voxelization.VoxelizedSection;
|
||||||
import me.cortex.voxy.common.world.other.Mapper;
|
import me.cortex.voxy.common.world.other.Mapper;
|
||||||
import me.cortex.voxy.common.world.service.SectionSavingService;
|
|
||||||
import me.cortex.voxy.common.world.service.VoxelIngestService;
|
|
||||||
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
//Use an LMDB backend to store the world, use a local inmemory cache for lod sections
|
|
||||||
// automatically manages and invalidates sections of the world as needed
|
|
||||||
public class WorldEngine {
|
public class WorldEngine {
|
||||||
public static final int MAX_LOD_LAYERS = 5;
|
public static final int MAX_LOD_LAYERS = 5;
|
||||||
|
|
||||||
@@ -22,36 +14,35 @@ public class WorldEngine {
|
|||||||
public static final int UPDATE_FLAGS = UPDATE_TYPE_BLOCK_BIT | UPDATE_TYPE_CHILD_EXISTENCE_BIT;
|
public static final int UPDATE_FLAGS = UPDATE_TYPE_BLOCK_BIT | UPDATE_TYPE_CHILD_EXISTENCE_BIT;
|
||||||
|
|
||||||
public interface ISectionChangeCallback {void accept(WorldSection section, int updateFlags);}
|
public interface ISectionChangeCallback {void accept(WorldSection section, int updateFlags);}
|
||||||
|
public interface ISectionSaveCallback {void save(WorldEngine engine, WorldSection section);}
|
||||||
|
|
||||||
|
|
||||||
public final SectionStorage storage;
|
public final SectionStorage storage;
|
||||||
private final Mapper mapper;
|
private final Mapper mapper;
|
||||||
private final ActiveSectionTracker sectionTracker;
|
private final ActiveSectionTracker sectionTracker;
|
||||||
public final VoxelIngestService ingestService;
|
|
||||||
public final SectionSavingService savingService;
|
|
||||||
private ISectionChangeCallback dirtyCallback;
|
private ISectionChangeCallback dirtyCallback;
|
||||||
|
private ISectionSaveCallback saveCallback;
|
||||||
private final int maxMipLevels;
|
private final int maxMipLevels;
|
||||||
|
|
||||||
public void setDirtyCallback(ISectionChangeCallback callback) {
|
public void setDirtyCallback(ISectionChangeCallback callback) {
|
||||||
this.dirtyCallback = callback;
|
this.dirtyCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mapper getMapper() {return this.mapper;}
|
public void setSaveCallback(ISectionSaveCallback callback) {
|
||||||
|
this.saveCallback = callback;
|
||||||
|
|
||||||
public WorldEngine(SectionStorage storage, ServiceThreadPool serviceThreadPool, int cacheCount) {
|
|
||||||
this(storage, serviceThreadPool, MAX_LOD_LAYERS, cacheCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private WorldEngine(SectionStorage storage, ServiceThreadPool serviceThreadPool, int maxMipLayers, int cacheCount) {
|
public Mapper getMapper() {return this.mapper;}
|
||||||
|
public WorldEngine(SectionStorage storage, int cacheCount) {
|
||||||
|
this(storage, MAX_LOD_LAYERS, cacheCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private WorldEngine(SectionStorage storage, int maxMipLayers, int cacheCount) {
|
||||||
this.maxMipLevels = maxMipLayers;
|
this.maxMipLevels = maxMipLayers;
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
this.mapper = new Mapper(this.storage);
|
this.mapper = new Mapper(this.storage);
|
||||||
//4 cache size bits means that the section tracker has 16 separate maps that it uses
|
//4 cache size bits means that the section tracker has 16 separate maps that it uses
|
||||||
this.sectionTracker = new ActiveSectionTracker(4, storage::loadSection, cacheCount);
|
this.sectionTracker = new ActiveSectionTracker(4, storage::loadSection, cacheCount, this);
|
||||||
|
|
||||||
this.savingService = new SectionSavingService(this, serviceThreadPool);
|
|
||||||
this.ingestService = new VoxelIngestService(this, serviceThreadPool);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldSection acquireIfExists(int lvl, int x, int y, int z) {
|
public WorldSection acquireIfExists(int lvl, int x, int y, int z) {
|
||||||
@@ -104,7 +95,9 @@ public class WorldEngine {
|
|||||||
if (this.dirtyCallback != null) {
|
if (this.dirtyCallback != null) {
|
||||||
this.dirtyCallback.accept(section, changeState);
|
this.dirtyCallback.accept(section, changeState);
|
||||||
}
|
}
|
||||||
this.savingService.enqueueSave(section);
|
if (this.saveCallback != null) {
|
||||||
|
this.saveCallback.save(this, section);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -207,10 +200,9 @@ public class WorldEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
try {this.storage.flush();} catch (Exception e) {e.printStackTrace();}
|
try {this.mapper.close();} catch (Exception e) {Logger.error(e);}
|
||||||
|
try {this.storage.flush();} catch (Exception e) {Logger.error(e);}
|
||||||
//Shutdown in this order to preserve as much data as possible
|
//Shutdown in this order to preserve as much data as possible
|
||||||
try {this.ingestService.shutdown();} catch (Exception e) {e.printStackTrace();}
|
try {this.storage.close();} catch (Exception e) {Logger.error(e);}
|
||||||
try {this.savingService.shutdown();} catch (Exception e) {e.printStackTrace();}
|
|
||||||
try {this.storage.close();} catch (Exception e) {e.printStackTrace();}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,4 +259,8 @@ public final class WorldSection {
|
|||||||
public static WorldSection _createRawUntrackedUnsafeSection(int lvl, int x, int y, int z) {
|
public static WorldSection _createRawUntrackedUnsafeSection(int lvl, int x, int y, int z) {
|
||||||
return new WorldSection(lvl, x, y, z, null);
|
return new WorldSection(lvl, x, y, z, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ActiveSectionTracker _getSectionTracker() {
|
||||||
|
return this.tracker;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -282,6 +282,10 @@ public class Mapper {
|
|||||||
this.storage.flush();
|
this.storage.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static final class StateEntry {
|
public static final class StateEntry {
|
||||||
public final int id;
|
public final int id;
|
||||||
|
|||||||
@@ -16,34 +16,40 @@ import java.util.concurrent.ConcurrentLinkedDeque;
|
|||||||
// might have some issues with threading if the same section is saved from multiple threads?
|
// might have some issues with threading if the same section is saved from multiple threads?
|
||||||
public class SectionSavingService {
|
public class SectionSavingService {
|
||||||
private final ServiceSlice threads;
|
private final ServiceSlice threads;
|
||||||
private final ConcurrentLinkedDeque<WorldSection> saveQueue = new ConcurrentLinkedDeque<>();
|
private record SaveEntry(WorldEngine engine, WorldSection section) {}
|
||||||
private final WorldEngine world;
|
private final ConcurrentLinkedDeque<SaveEntry> saveQueue = new ConcurrentLinkedDeque<>();
|
||||||
|
|
||||||
public SectionSavingService(WorldEngine worldEngine, ServiceThreadPool threadPool) {
|
public SectionSavingService(ServiceThreadPool threadPool) {
|
||||||
this.world = worldEngine;
|
|
||||||
this.threads = threadPool.createServiceNoCleanup("Section saving service", 100, () -> this::processJob);
|
this.threads = threadPool.createServiceNoCleanup("Section saving service", 100, () -> this::processJob);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processJob() {
|
private void processJob() {
|
||||||
var section = this.saveQueue.pop();
|
var task = this.saveQueue.pop();
|
||||||
|
var section = task.section;
|
||||||
section.assertNotFree();
|
section.assertNotFree();
|
||||||
try {
|
try {
|
||||||
section.inSaveQueue.set(false);
|
section.inSaveQueue.set(false);
|
||||||
this.world.storage.saveSection(section);
|
task.engine.storage.saveSection(section);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String err = "Voxy saver had an exception while executing please check logs and report error";
|
Logger.error("Voxy saver had an exception while executing please check logs and report error", e);
|
||||||
Logger.error(err, e);
|
|
||||||
MinecraftClient.getInstance().executeSync(()->MinecraftClient.getInstance().player.sendMessage(Text.literal(err), true));
|
|
||||||
}
|
}
|
||||||
section.release();
|
section.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enqueueSave(WorldSection section) {
|
public void enqueueSave(WorldSection section) {
|
||||||
|
if (section._getSectionTracker() != null && section._getSectionTracker().engine != null) {
|
||||||
|
this.enqueueSave(section._getSectionTracker().engine, section);
|
||||||
|
} else {
|
||||||
|
Logger.error("Tried saving world section, but did not have world associated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enqueueSave(WorldEngine in, WorldSection section) {
|
||||||
//If its not enqueued for saving then enqueue it
|
//If its not enqueued for saving then enqueue it
|
||||||
if (!section.inSaveQueue.getAndSet(true)) {
|
if (!section.inSaveQueue.getAndSet(true)) {
|
||||||
//Acquire the section for use
|
//Acquire the section for use
|
||||||
section.acquire();
|
section.acquire();
|
||||||
this.saveQueue.add(section);
|
this.saveQueue.add(new SaveEntry(in, section));
|
||||||
this.threads.execute();
|
this.threads.execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package me.cortex.voxy.common.world.service;
|
package me.cortex.voxy.common.world.service;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.Pair;
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
|
import me.cortex.voxy.common.Logger;
|
||||||
import me.cortex.voxy.common.voxelization.ILightingSupplier;
|
import me.cortex.voxy.common.voxelization.ILightingSupplier;
|
||||||
import me.cortex.voxy.common.voxelization.VoxelizedSection;
|
import me.cortex.voxy.common.voxelization.VoxelizedSection;
|
||||||
import me.cortex.voxy.common.voxelization.WorldConversionFactory;
|
import me.cortex.voxy.common.voxelization.WorldConversionFactory;
|
||||||
import me.cortex.voxy.common.world.WorldEngine;
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
import me.cortex.voxy.common.thread.ServiceSlice;
|
import me.cortex.voxy.common.thread.ServiceSlice;
|
||||||
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
||||||
|
import me.cortex.voxy.commonImpl.IVoxyWorldGetter;
|
||||||
import net.minecraft.util.math.ChunkSectionPos;
|
import net.minecraft.util.math.ChunkSectionPos;
|
||||||
import net.minecraft.world.LightType;
|
import net.minecraft.world.LightType;
|
||||||
import net.minecraft.world.chunk.ChunkNibbleArray;
|
import net.minecraft.world.chunk.ChunkNibbleArray;
|
||||||
@@ -20,12 +22,10 @@ import java.util.concurrent.ConcurrentLinkedDeque;
|
|||||||
public class VoxelIngestService {
|
public class VoxelIngestService {
|
||||||
private static final ThreadLocal<VoxelizedSection> SECTION_CACHE = ThreadLocal.withInitial(VoxelizedSection::createEmpty);
|
private static final ThreadLocal<VoxelizedSection> SECTION_CACHE = ThreadLocal.withInitial(VoxelizedSection::createEmpty);
|
||||||
private final ServiceSlice threads;
|
private final ServiceSlice threads;
|
||||||
private record IngestSection(int cx, int cy, int cz, ChunkSection section, ChunkNibbleArray blockLight, ChunkNibbleArray skyLight){}
|
private record IngestSection(int cx, int cy, int cz, WorldEngine world, ChunkSection section, ChunkNibbleArray blockLight, ChunkNibbleArray skyLight){}
|
||||||
private final ConcurrentLinkedDeque<IngestSection> ingestQueue = new ConcurrentLinkedDeque<>();
|
private final ConcurrentLinkedDeque<IngestSection> ingestQueue = new ConcurrentLinkedDeque<>();
|
||||||
|
|
||||||
private final WorldEngine world;
|
public VoxelIngestService(ServiceThreadPool pool) {
|
||||||
public VoxelIngestService(WorldEngine world, ServiceThreadPool pool) {
|
|
||||||
this.world = world;
|
|
||||||
this.threads = pool.createServiceNoCleanup("Ingest service", 100, ()-> this::processJob);
|
this.threads = pool.createServiceNoCleanup("Ingest service", 100, ()-> this::processJob);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ public class VoxelIngestService {
|
|||||||
var vs = SECTION_CACHE.get().setPosition(task.cx, task.cy, task.cz);
|
var vs = SECTION_CACHE.get().setPosition(task.cx, task.cy, task.cz);
|
||||||
|
|
||||||
if (section.isEmpty() && task.blockLight==null && task.skyLight==null) {//If the chunk section has lighting data, propagate it
|
if (section.isEmpty() && task.blockLight==null && task.skyLight==null) {//If the chunk section has lighting data, propagate it
|
||||||
this.world.insertUpdate(vs.zero());
|
task.world.insertUpdate(vs.zero());
|
||||||
} else {
|
} else {
|
||||||
ILightingSupplier supplier = (x,y,z) -> (byte) 0;
|
ILightingSupplier supplier = (x,y,z) -> (byte) 0;
|
||||||
var sla = task.skyLight;
|
var sla = task.skyLight;
|
||||||
@@ -65,13 +65,13 @@ public class VoxelIngestService {
|
|||||||
}
|
}
|
||||||
VoxelizedSection csec = WorldConversionFactory.convert(
|
VoxelizedSection csec = WorldConversionFactory.convert(
|
||||||
SECTION_CACHE.get(),
|
SECTION_CACHE.get(),
|
||||||
this.world.getMapper(),
|
task.world.getMapper(),
|
||||||
section.getBlockStateContainer(),
|
section.getBlockStateContainer(),
|
||||||
section.getBiomeContainer(),
|
section.getBiomeContainer(),
|
||||||
supplier
|
supplier
|
||||||
);
|
);
|
||||||
WorldConversionFactory.mipSection(csec, this.world.getMapper());
|
WorldConversionFactory.mipSection(csec, task.world.getMapper());
|
||||||
this.world.insertUpdate(csec);
|
task.world.insertUpdate(csec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +80,15 @@ public class VoxelIngestService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void enqueueIngest(WorldChunk chunk) {
|
public void enqueueIngest(WorldChunk chunk) {
|
||||||
|
var engine = ((IVoxyWorldGetter)chunk.getWorld()).getWorldEngine();
|
||||||
|
if (engine == null) {
|
||||||
|
Logger.error("Could not ingest chunk as does not have world engine");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.enqueueIngest(engine, chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enqueueIngest(WorldEngine engine, WorldChunk chunk) {
|
||||||
var lightingProvider = chunk.getWorld().getLightingProvider();
|
var lightingProvider = chunk.getWorld().getLightingProvider();
|
||||||
var blp = lightingProvider.get(LightType.BLOCK);
|
var blp = lightingProvider.get(LightType.BLOCK);
|
||||||
var slp = lightingProvider.get(LightType.SKY);
|
var slp = lightingProvider.get(LightType.SKY);
|
||||||
@@ -107,7 +116,7 @@ public class VoxelIngestService {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ingestQueue.add(new IngestSection(chunk.getPos().x, i, chunk.getPos().z, section, bl, sl));
|
this.ingestQueue.add(new IngestSection(chunk.getPos().x, i, chunk.getPos().z, engine, section, bl, sl));
|
||||||
this.threads.execute();
|
this.threads.execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import net.fabricmc.loader.api.FabricLoader;
|
|||||||
import net.fabricmc.loader.api.ModContainer;
|
import net.fabricmc.loader.api.ModContainer;
|
||||||
|
|
||||||
public class VoxyCommon implements ModInitializer {
|
public class VoxyCommon implements ModInitializer {
|
||||||
|
private static VoxyInstance INSTANCE;
|
||||||
|
|
||||||
public static final String MOD_VERSION;
|
public static final String MOD_VERSION;
|
||||||
public static final boolean IS_DEDICATED_SERVER;
|
public static final boolean IS_DEDICATED_SERVER;
|
||||||
|
|
||||||
@@ -27,11 +29,6 @@ public class VoxyCommon implements ModInitializer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
//this.serviceThreadPool = new ServiceThreadPool(VoxyConfig.CONFIG.serviceThreads);
|
|
||||||
|
|
||||||
//TODO: need to have a common config with server/client configs deriving from it
|
|
||||||
// maybe server/client extend it? or something? cause like client needs server config (at least partially sometimes)
|
|
||||||
// but server doesnt need client config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void breakpoint() {
|
public static void breakpoint() {
|
||||||
@@ -44,4 +41,22 @@ public class VoxyCommon implements ModInitializer {
|
|||||||
public static boolean isVerificationFlagOn(String name) {
|
public static boolean isVerificationFlagOn(String name) {
|
||||||
return (!GlobalVerificationDisableOverride) && System.getProperty("voxy."+name, "true").equals("true");
|
return (!GlobalVerificationDisableOverride) && System.getProperty("voxy."+name, "true").equals("true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static VoxyInstance getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void shutdownInstance() {
|
||||||
|
if (INSTANCE != null) {
|
||||||
|
INSTANCE.shutdown();
|
||||||
|
INSTANCE = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void createInstance() {
|
||||||
|
if (INSTANCE != null) {
|
||||||
|
throw new IllegalStateException("Cannot create multiple instances");
|
||||||
|
}
|
||||||
|
INSTANCE = new VoxyInstance(12);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
75
src/main/java/me/cortex/voxy/commonImpl/VoxyInstance.java
Normal file
75
src/main/java/me/cortex/voxy/commonImpl/VoxyInstance.java
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package me.cortex.voxy.commonImpl;
|
||||||
|
|
||||||
|
import me.cortex.voxy.client.saver.ContextSelectionSystem;
|
||||||
|
import me.cortex.voxy.common.Logger;
|
||||||
|
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
||||||
|
import me.cortex.voxy.common.util.MemoryBuffer;
|
||||||
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
|
import me.cortex.voxy.common.world.service.SectionSavingService;
|
||||||
|
import me.cortex.voxy.common.world.service.VoxelIngestService;
|
||||||
|
import net.minecraft.client.world.ClientWorld;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class VoxyInstance {
|
||||||
|
private final ServiceThreadPool threadPool;
|
||||||
|
private final SectionSavingService savingService;
|
||||||
|
private final VoxelIngestService ingestService;
|
||||||
|
|
||||||
|
public VoxyInstance(int threadCount) {
|
||||||
|
this.threadPool = new ServiceThreadPool(threadCount);
|
||||||
|
this.savingService = new SectionSavingService(this.threadPool);
|
||||||
|
this.ingestService = new VoxelIngestService(this.threadPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDebug(List<String> debug) {
|
||||||
|
debug.add("Voxy Core: " + VoxyCommon.MOD_VERSION);
|
||||||
|
debug.add("MemoryBuffer, Count/Size (mb): " + MemoryBuffer.getCount() + "/" + (MemoryBuffer.getTotalSize()/1_000_000));
|
||||||
|
debug.add("I/S: " + this.ingestService.getTaskCount() + "/" + this.savingService.getTaskCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
Logger.info("Shutdown voxy instance");
|
||||||
|
try {this.ingestService.shutdown();} catch (Exception e) {Logger.error(e);}
|
||||||
|
try {this.savingService.shutdown();} catch (Exception e) {Logger.error(e);}
|
||||||
|
try {this.threadPool.shutdown();} catch (Exception e) {Logger.error(e);}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceThreadPool getThreadPool() {
|
||||||
|
return this.threadPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VoxelIngestService getIngestService() {
|
||||||
|
return this.ingestService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SectionSavingService getSavingService() {
|
||||||
|
return this.savingService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
try {
|
||||||
|
while (this.ingestService.getTaskCount() != 0) {
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
while (this.savingService.getTaskCount() != 0) {
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final ContextSelectionSystem SELECTOR = new ContextSelectionSystem();
|
||||||
|
|
||||||
|
public WorldEngine getOrMakeWorld(ClientWorld world) {
|
||||||
|
var vworld = ((IVoxyWorldGetter)world).getWorldEngine();
|
||||||
|
if (vworld == null) {
|
||||||
|
vworld = new WorldEngine(SELECTOR.getBestSelectionOrCreate(world).createSectionStorageBackend(), 1024);
|
||||||
|
vworld.setSaveCallback(this.savingService::enqueueSave);
|
||||||
|
((IVoxyWorldSetter)world).setWorldEngine(vworld);
|
||||||
|
}
|
||||||
|
return vworld;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import me.cortex.voxy.common.voxelization.WorldConversionFactory;
|
|||||||
import me.cortex.voxy.common.world.WorldEngine;
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
import me.cortex.voxy.common.thread.ServiceSlice;
|
import me.cortex.voxy.common.thread.ServiceSlice;
|
||||||
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
||||||
|
import me.cortex.voxy.common.world.service.SectionSavingService;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
@@ -37,6 +38,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
@@ -57,9 +59,13 @@ public class WorldImporter {
|
|||||||
private final ServiceSlice threadPool;
|
private final ServiceSlice threadPool;
|
||||||
|
|
||||||
private volatile boolean isRunning;
|
private volatile boolean isRunning;
|
||||||
public WorldImporter(WorldEngine worldEngine, World mcWorld, ServiceThreadPool servicePool) {
|
public WorldImporter(WorldEngine worldEngine, World mcWorld, ServiceThreadPool servicePool, SectionSavingService savingService) {
|
||||||
|
this(worldEngine, mcWorld, servicePool, ()->savingService.getTaskCount() < 4000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorldImporter(WorldEngine worldEngine, World mcWorld, ServiceThreadPool servicePool, BooleanSupplier runChecker) {
|
||||||
this.world = worldEngine;
|
this.world = worldEngine;
|
||||||
this.threadPool = servicePool.createServiceNoCleanup("World importer", 1, ()->()->this.jobQueue.poll().run(), ()->this.world.savingService.getTaskCount() < 4000);
|
this.threadPool = servicePool.createServiceNoCleanup("World importer", 1, ()->()->this.jobQueue.poll().run(), runChecker);
|
||||||
|
|
||||||
var biomeRegistry = mcWorld.getRegistryManager().getOrThrow(RegistryKeys.BIOME);
|
var biomeRegistry = mcWorld.getRegistryManager().getOrThrow(RegistryKeys.BIOME);
|
||||||
var defaultBiome = biomeRegistry.getOrThrow(BiomeKeys.PLAINS);
|
var defaultBiome = biomeRegistry.getOrThrow(BiomeKeys.PLAINS);
|
||||||
|
|||||||
@@ -1,31 +1,18 @@
|
|||||||
package me.cortex.voxy.client.mixin.chunky;
|
package me.cortex.voxy.commonImpl.mixin.chunky;
|
||||||
|
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
import me.cortex.voxy.client.Voxy;
|
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||||
import me.cortex.voxy.client.config.VoxyConfig;
|
|
||||||
import me.cortex.voxy.client.core.IGetVoxelCore;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
|
||||||
import net.minecraft.server.world.ChunkHolder;
|
|
||||||
import net.minecraft.server.world.OptionalChunk;
|
import net.minecraft.server.world.OptionalChunk;
|
||||||
import net.minecraft.server.world.ServerChunkLoadingManager;
|
|
||||||
import net.minecraft.server.world.ServerWorld;
|
|
||||||
import net.minecraft.world.chunk.Chunk;
|
import net.minecraft.world.chunk.Chunk;
|
||||||
import net.minecraft.world.chunk.ChunkStatus;
|
import net.minecraft.world.chunk.ChunkStatus;
|
||||||
import net.minecraft.world.chunk.WorldChunk;
|
import net.minecraft.world.chunk.WorldChunk;
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.popcraft.chunky.mixin.ServerChunkCacheMixin;
|
import org.popcraft.chunky.mixin.ServerChunkCacheMixin;
|
||||||
import org.popcraft.chunky.platform.FabricWorld;
|
import org.popcraft.chunky.platform.FabricWorld;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
|
|
||||||
@Mixin(FabricWorld.class)
|
@Mixin(FabricWorld.class)
|
||||||
public class MixinFabricWorld {
|
public class MixinFabricWorld {
|
||||||
@@ -34,9 +21,9 @@ public class MixinFabricWorld {
|
|||||||
var future = original.call(instance, i, j, chunkStatus, b);
|
var future = original.call(instance, i, j, chunkStatus, b);
|
||||||
return future.thenApplyAsync(res->{
|
return future.thenApplyAsync(res->{
|
||||||
res.ifPresent(chunk -> {
|
res.ifPresent(chunk -> {
|
||||||
var core = ((IGetVoxelCore)(MinecraftClient.getInstance().worldRenderer)).getVoxelCore();
|
var voxyInstance = VoxyCommon.getInstance();
|
||||||
if (core != null && VoxyConfig.CONFIG.ingestEnabled) {
|
if (voxyInstance != null) {
|
||||||
core.enqueueIngest((WorldChunk) chunk);
|
voxyInstance.getIngestService().enqueueIngest((WorldChunk) chunk);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return res;
|
return res;
|
||||||
@@ -3,12 +3,11 @@
|
|||||||
"package": "me.cortex.voxy.client.mixin",
|
"package": "me.cortex.voxy.client.mixin",
|
||||||
"compatibilityLevel": "JAVA_17",
|
"compatibilityLevel": "JAVA_17",
|
||||||
"client": [
|
"client": [
|
||||||
"chunky.MixinFabricWorld",
|
|
||||||
"joml.AccessFrustumIntersection",
|
"joml.AccessFrustumIntersection",
|
||||||
"minecraft.MixinClientCommonNetworkHandler",
|
"minecraft.MixinClientCommonNetworkHandler",
|
||||||
"minecraft.MixinThreadExecutor",
|
|
||||||
"minecraft.MixinDebugHud",
|
"minecraft.MixinDebugHud",
|
||||||
"minecraft.MixinMinecraftClient",
|
"minecraft.MixinMinecraftClient",
|
||||||
|
"minecraft.MixinThreadExecutor",
|
||||||
"minecraft.MixinWorldRenderer",
|
"minecraft.MixinWorldRenderer",
|
||||||
"sodium.MixinDefaultChunkRenderer",
|
"sodium.MixinDefaultChunkRenderer",
|
||||||
"sodium.MixinRenderSectionManager"
|
"sodium.MixinRenderSectionManager"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
},
|
},
|
||||||
"mixins": [
|
"mixins": [
|
||||||
|
"chunky.MixinFabricWorld",
|
||||||
"minecraft.MixinWorld"
|
"minecraft.MixinWorld"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"environment": "*",
|
"environment": "*",
|
||||||
"entrypoints": {
|
"entrypoints": {
|
||||||
"client": [
|
"client": [
|
||||||
"me.cortex.voxy.client.Voxy"
|
"me.cortex.voxy.client.VoxyClient"
|
||||||
],
|
],
|
||||||
"modmenu": [
|
"modmenu": [
|
||||||
"me.cortex.voxy.client.config.VoxyConfigScreenFactory"
|
"me.cortex.voxy.client.config.VoxyConfigScreenFactory"
|
||||||
|
|||||||
Reference in New Issue
Block a user