diff --git a/build.gradle b/build.gradle index d55a0c3d..809df20a 100644 --- a/build.gradle +++ b/build.gradle @@ -52,6 +52,9 @@ dependencies { modRuntimeOnly "maven.modrinth:sodium:mc1.20.4-0.5.8" modCompileOnly "maven.modrinth:sodium:mc1.20.4-0.5.8" + //modRuntimeOnly "maven.modrinth:nvidium:0.2.6-beta" + modCompileOnly "maven.modrinth:nvidium:0.2.6-beta" + modImplementation("maven.modrinth:cloth-config:13.0.121+fabric") modImplementation("maven.modrinth:modmenu:9.0.0") modCompileOnly("maven.modrinth:iris:1.6.17+1.20.4") diff --git a/gradle.properties b/gradle.properties index e862c534..e33c365e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ yarn_mappings=1.20.4+build.1 loader_version=0.15.0 # Mod Properties -mod_version = 0.1.0-alpha +mod_version = 0.1.1-alpha maven_group = me.cortex archives_base_name = voxy diff --git a/src/main/java/me/cortex/voxy/client/Voxy.java b/src/main/java/me/cortex/voxy/client/Voxy.java index 9680dcde..b947c8db 100644 --- a/src/main/java/me/cortex/voxy/client/Voxy.java +++ b/src/main/java/me/cortex/voxy/client/Voxy.java @@ -6,9 +6,18 @@ import me.cortex.voxy.client.terrain.WorldImportCommand; import me.cortex.voxy.common.storage.config.Serialization; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; import net.minecraft.client.world.ClientWorld; public class Voxy implements ClientModInitializer { + public static final String VERSION; + + static { + ModContainer mod = (ModContainer) FabricLoader.getInstance().getModContainer("voxy").orElseThrow(NullPointerException::new); + VERSION = mod.getMetadata().getVersion().getFriendlyString(); + } + @Override public void onInitializeClient() { Serialization.init(); diff --git a/src/main/java/me/cortex/voxy/client/config/VoxyConfigScreenFactory.java b/src/main/java/me/cortex/voxy/client/config/VoxyConfigScreenFactory.java index 042b3ba2..fc862c3d 100644 --- a/src/main/java/me/cortex/voxy/client/config/VoxyConfigScreenFactory.java +++ b/src/main/java/me/cortex/voxy/client/config/VoxyConfigScreenFactory.java @@ -73,7 +73,7 @@ public class VoxyConfigScreenFactory implements ModMenuApi { .setDefaultValue(DEFAULT.ingestEnabled) .build()); - category.addEntry(entryBuilder.startIntSlider(Text.translatable("voxy.config.general.quality"), config.qualityScale, 8, 50) + category.addEntry(entryBuilder.startIntSlider(Text.translatable("voxy.config.general.quality"), config.qualityScale, 8, 32) .setTooltip(Text.translatable("voxy.config.general.quality.tooltip")) .setSaveConsumer(val -> config.qualityScale = val) .setDefaultValue(DEFAULT.qualityScale) @@ -103,19 +103,19 @@ public class VoxyConfigScreenFactory implements ModMenuApi { ConfigEntryBuilder entryBuilder = builder.entryBuilder(); category.addEntry(entryBuilder.startIntSlider(Text.translatable("voxy.config.threads.ingest"), config.ingestThreads, 1, Runtime.getRuntime().availableProcessors()) - .setTooltip(Text.translatable("voxy.config.general.ingest.tooltip")) + .setTooltip(Text.translatable("voxy.config.ingest.tooltip")) .setSaveConsumer(val -> config.ingestThreads = val) .setDefaultValue(DEFAULT.ingestThreads) .build()); category.addEntry(entryBuilder.startIntSlider(Text.translatable("voxy.config.threads.saving"), config.savingThreads, 1, Runtime.getRuntime().availableProcessors()) - .setTooltip(Text.translatable("voxy.config.general.saving.tooltip")) + .setTooltip(Text.translatable("voxy.config.saving.tooltip")) .setSaveConsumer(val -> config.savingThreads = val) .setDefaultValue(DEFAULT.savingThreads) .build()); category.addEntry(entryBuilder.startIntSlider(Text.translatable("voxy.config.threads.render"), config.renderThreads, 1, Runtime.getRuntime().availableProcessors()) - .setTooltip(Text.translatable("voxy.config.general.render.tooltip")) + .setTooltip(Text.translatable("voxy.config.render.tooltip")) .setSaveConsumer(val -> config.renderThreads = val) .setDefaultValue(DEFAULT.renderThreads) .build()); diff --git a/src/main/java/me/cortex/voxy/client/core/VoxelCore.java b/src/main/java/me/cortex/voxy/client/core/VoxelCore.java index 6b1d6fea..ba546cf3 100644 --- a/src/main/java/me/cortex/voxy/client/core/VoxelCore.java +++ b/src/main/java/me/cortex/voxy/client/core/VoxelCore.java @@ -2,6 +2,7 @@ package me.cortex.voxy.client.core; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; +import me.cortex.voxy.client.Voxy; import me.cortex.voxy.client.config.VoxyConfig; import me.cortex.voxy.client.core.rendering.*; import me.cortex.voxy.client.core.rendering.building.RenderGenerationService; @@ -113,7 +114,7 @@ public class VoxelCore { this.renderer.setupRender(frustum, camera); } - private Matrix4f getProjectionMatrix() { + 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(); @@ -124,11 +125,14 @@ public class VoxelCore { projection.setPerspective(fov * 0.01745329238474369f, (float) client.getWindow().getFramebufferWidth() / (float)client.getWindow().getFramebufferHeight(), - 16F, 16 * 3000f); - var transform = new Matrix4f().identity(); - transform.translate(gameRenderer.zoomX, -gameRenderer.zoomY, 0.0F); - transform.scale(gameRenderer.zoom, gameRenderer.zoom, 1.0F); - return transform.mul(projection); + near, far); + return projection; + } + + private static Matrix4f computeProjectionMat() { + return new Matrix4f(RenderSystem.getProjectionMatrix()).mulLocal( + makeProjectionMatrix(0.05f, MinecraftClient.getInstance().gameRenderer.getFarPlaneDistance()).invert() + ).mulLocal(makeProjectionMatrix(16, 16*3000)); } public void renderOpaque(MatrixStack matrices, double cameraX, double cameraY, double cameraZ) { @@ -159,7 +163,7 @@ public class VoxelCore { // this is cause the terrain might not exist and so all the caves are visible causing hell for the // occlusion culler - var projection = this.getProjectionMatrix(); + var projection = computeProjectionMat(); this.renderer.renderFarAwayOpaque(projection, matrices, cameraX, cameraY, cameraZ); @@ -177,7 +181,7 @@ public class VoxelCore { public void addDebugInfo(List debug) { debug.add(""); debug.add(""); - debug.add("Voxy Core"); + debug.add("Voxy Core: " + Voxy.VERSION); debug.add("Ingest service tasks: " + this.world.ingestService.getTaskCount()); debug.add("Saving service tasks: " + this.world.savingService.getTaskCount()); debug.add("Render service tasks: " + this.renderGen.getTaskCount()); @@ -208,7 +212,7 @@ public class VoxelCore { public WorldImporter createWorldImporter(World mcWorld, File worldPath) { var importer = new WorldImporter(this.world, mcWorld); - importer.importWorldAsyncStart(worldPath, 15, null, ()->{ + importer.importWorldAsyncStart(worldPath, 4, null, ()->{ System.err.println("DONE IMPORT"); }); return importer; diff --git a/src/main/java/me/cortex/voxy/client/core/model/ModelManager.java b/src/main/java/me/cortex/voxy/client/core/model/ModelManager.java index e498dd3e..842816ed 100644 --- a/src/main/java/me/cortex/voxy/client/core/model/ModelManager.java +++ b/src/main/java/me/cortex/voxy/client/core/model/ModelManager.java @@ -148,7 +148,8 @@ public class ModelManager { // while the depth is computed from the depth buffer data public int addEntry(int blockId, BlockState blockState) { if (this.idMappings[blockId] != -1) { - throw new IllegalArgumentException("Trying to add entry for duplicate id"); + System.err.println("Block id already added: " + blockId + " for state: " + blockState); + return this.idMappings[blockId]; } boolean isFluid = blockState.getBlock() instanceof FluidBlock; diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/GeometryManager.java b/src/main/java/me/cortex/voxy/client/core/rendering/GeometryManager.java index 31d89bed..9fcece60 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/GeometryManager.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/GeometryManager.java @@ -7,6 +7,8 @@ import me.cortex.voxy.client.core.gl.GlBuffer; import me.cortex.voxy.client.core.rendering.building.BuiltSection; import me.cortex.voxy.client.core.rendering.util.BufferArena; import me.cortex.voxy.client.core.rendering.util.UploadStream; +import net.minecraft.client.MinecraftClient; +import net.minecraft.text.Text; import org.lwjgl.system.MemoryUtil; import java.util.concurrent.ConcurrentLinkedDeque; @@ -79,6 +81,9 @@ public class GeometryManager { //Create the new meta meta = this.createMeta(result); + if (meta == null) { + continue; + } this.sectionMetadata.set(id, meta); long ptr = UploadStream.INSTANCE.upload(this.sectionMetaBuffer, (long)SECTION_METADATA_SIZE * id, SECTION_METADATA_SIZE); meta.writeMetadata(ptr); @@ -90,6 +95,9 @@ public class GeometryManager { //Create the new meta var meta = this.createMeta(result); + if (meta == null) { + continue; + } this.sectionMetadata.add(meta); long ptr = UploadStream.INSTANCE.upload(this.sectionMetaBuffer, (long)SECTION_METADATA_SIZE * id, SECTION_METADATA_SIZE); meta.writeMetadata(ptr); @@ -158,6 +166,12 @@ public class GeometryManager { private SectionMeta createMeta(BuiltSection geometry) { int geometryPtr = (int) this.geometryBuffer.upload(geometry.geometryBuffer); + if (geometryPtr == -1) { + String msg = "Buffer arena out of memory, please increase it in settings or decrease LoD quality"; + MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(Text.literal(msg)); + System.err.println(msg); + return null; + } return new SectionMeta(geometry.position, geometry.aabb, geometryPtr, (int) (geometry.geometryBuffer.size/8), geometry.offsets); } diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/building/BuiltSectionMeshCache.java b/src/main/java/me/cortex/voxy/client/core/rendering/building/BuiltSectionMeshCache.java index cd043580..2e5bb41e 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/building/BuiltSectionMeshCache.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/building/BuiltSectionMeshCache.java @@ -14,7 +14,7 @@ public class BuiltSectionMeshCache { public BuiltSection getMesh(long key) { BuiltSection[] res = new BuiltSection[1]; this.renderCache.computeIfPresent(key, (a, value) -> { - if (value == null || value == HOLDER) { + if (value == HOLDER) { return value; } res[0] = value.clone(); diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/util/BufferArena.java b/src/main/java/me/cortex/voxy/client/core/rendering/util/BufferArena.java index a7a4043a..0edf233c 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/util/BufferArena.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/util/BufferArena.java @@ -29,7 +29,7 @@ public class BufferArena { int size = (int) (buffer.size/this.elementSize); long addr = this.allocationMap.alloc(size); if (addr == -1) { - throw new IllegalStateException("Buffer arena out of memory"); + return -1; } long uploadPtr = UploadStream.INSTANCE.upload(this.buffer, addr * this.elementSize, buffer.size); MemoryUtil.memCopy(buffer.address, uploadPtr, buffer.size); diff --git a/src/main/java/me/cortex/voxy/client/mixin/nvidium/MixinRenderPipeline.java b/src/main/java/me/cortex/voxy/client/mixin/nvidium/MixinRenderPipeline.java new file mode 100644 index 00000000..6e433723 --- /dev/null +++ b/src/main/java/me/cortex/voxy/client/mixin/nvidium/MixinRenderPipeline.java @@ -0,0 +1,29 @@ +package me.cortex.voxy.client.mixin.nvidium; + +import me.cortex.nvidium.RenderPipeline; +import me.cortex.voxy.client.config.VoxyConfig; +import me.cortex.voxy.client.core.IGetVoxelCore; +import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderMatrices; +import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; +import me.jellysquid.mods.sodium.client.render.viewport.Viewport; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.util.math.MatrixStack; +import org.joml.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = RenderPipeline.class, remap = false) +public class MixinRenderPipeline { + @Inject(method = "renderFrame", at = @At("RETURN")) + private void injectVoxyRender(Viewport frustum, ChunkRenderMatrices crm, double px, double py, double pz, CallbackInfo ci) { + var core = ((IGetVoxelCore) MinecraftClient.getInstance().worldRenderer).getVoxelCore(); + if (core != null) { + var stack = new MatrixStack(); + stack.loadIdentity(); + stack.multiplyPositionMatrix(new Matrix4f(crm.modelView())); + core.renderOpaque(stack, px, py, pz); + } + } +} diff --git a/src/main/java/me/cortex/voxy/client/mixin/sodium/MixinOcclusionCuller.java b/src/main/java/me/cortex/voxy/client/mixin/sodium/MixinOcclusionCuller.java deleted file mode 100644 index 8fbf95ac..00000000 --- a/src/main/java/me/cortex/voxy/client/mixin/sodium/MixinOcclusionCuller.java +++ /dev/null @@ -1,14 +0,0 @@ -package me.cortex.voxy.client.mixin.sodium; - -import me.jellysquid.mods.sodium.client.render.chunk.occlusion.OcclusionCuller; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(value = OcclusionCuller.class, remap = false) -public class MixinOcclusionCuller { - @Redirect(method = "isOutsideRenderDistance", at = @At(value = "INVOKE", target = "Ljava/lang/Math;abs(F)F"), require = 0) - private static float redirectAbs(float a) { - return 0; - } -} diff --git a/src/main/java/me/cortex/voxy/common/storage/config/Serialization.java b/src/main/java/me/cortex/voxy/common/storage/config/Serialization.java index 49611369..af9eded0 100644 --- a/src/main/java/me/cortex/voxy/common/storage/config/Serialization.java +++ b/src/main/java/me/cortex/voxy/common/storage/config/Serialization.java @@ -142,18 +142,23 @@ public class Serialization { } private static List collectAllClasses(String pack) { - InputStream stream = Serialization.class.getClassLoader() - .getResourceAsStream(pack.replaceAll("[.]", "/")); - BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); - return reader.lines().flatMap(inner -> { - if (inner.endsWith(".class")) { - return Stream.of(pack + "." + inner.replace(".class", "")); - } else if (!inner.contains(".")) { - return collectAllClasses(pack + "." + inner).stream(); - } else { - return Stream.of(); - } - }).collect(Collectors.toList()); + try { + InputStream stream = Serialization.class.getClassLoader() + .getResourceAsStream(pack.replaceAll("[.]", "/")); + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + return reader.lines().flatMap(inner -> { + if (inner.endsWith(".class")) { + return Stream.of(pack + "." + inner.replace(".class", "")); + } else if (!inner.contains(".")) { + return collectAllClasses(pack + "." + inner).stream(); + } else { + return Stream.of(); + } + }).collect(Collectors.toList()); + } catch (Exception e) { + System.err.println("Failed to collect classes in package: " + pack); + return List.of(); + } } private static List collectAllClasses(Path base, String pack) { if (!Files.exists(base.resolve(pack.replaceAll("[.]", "/")))) { diff --git a/src/main/resources/assets/voxy/icon.png b/src/main/resources/assets/voxy/icon.png index 40d22de5..77974ec4 100644 Binary files a/src/main/resources/assets/voxy/icon.png and b/src/main/resources/assets/voxy/icon.png differ diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 557a628b..2c2b109a 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -2,8 +2,8 @@ "schemaVersion": 1, "id": "voxy", "version": "${version}", - "name": "voxy", - "description": "", + "name": "Voxy", + "description": "Far distance rendering mod utilising LoDs", "authors": [ "Cortex" ], @@ -24,7 +24,10 @@ "voxy.mixins.json" ], "depends": { - "fabricloader": ">=0.14.22" + "minecraft": "1.20.4", + "fabricloader": ">=0.14.22", + "fabric-api": ">=0.91.1", + "sodium": "*" }, "accessWidener": "voxy.accesswidener" } diff --git a/src/main/resources/voxy.mixins.json b/src/main/resources/voxy.mixins.json index 396373ac..1695a8b6 100644 --- a/src/main/resources/voxy.mixins.json +++ b/src/main/resources/voxy.mixins.json @@ -9,13 +9,13 @@ "minecraft.MixinDebugHud", "minecraft.MixinMinecraftClient", "minecraft.MixinWorldRenderer", - "sodium.MixinOcclusionCuller", "sodium.MixinSodiumWorldRender" ], "injectors": { "defaultRequire": 1 }, "mixins": [ + "nvidium.MixinRenderPipeline", "sodium.MixinDefaultChunkRenderer", "sodium.MixinRenderSectionManager" ]