Compare commits

...

72 Commits

Author SHA1 Message Date
James Seibel 0b691ebcd5 remove dev from version number 2026-04-18 21:43:46 -05:00
James Seibel 3c35c52803 make mod loader name order consistent 2026-04-18 21:43:13 -05:00
James Seibel 0ed4964ee5 Fix MC 1.18 and older compiling 2026-04-18 20:12:43 -05:00
James Seibel b7cf7b61c8 Fix underwater grids and air handling
Some constructor methods weren't static so it was possible to pass in incorrect info, this has been fixed.
2026-04-18 20:01:12 -05:00
James Seibel 54b0ccfce6 add mod loaders to the merged jars 2026-04-18 15:48:44 -05:00
James Seibel 050d00b628 up MC 26 dev version to 26.1.2
Doesn't change compiling any, just makes it so dev testing is done on MC 26.1.2
2026-04-18 15:48:32 -05:00
James Seibel 2733201ac3 set the API jar in the gradle.properties
done for consistency
2026-04-18 15:47:54 -05:00
James Seibel 26bf03205c build all scripts don't double-merge jars
jar merging handled automatically now
2026-04-18 11:25:22 -05:00
James Seibel 628d57d216 remove google-collect 2026-04-18 11:09:23 -05:00
James Seibel 58ed8259f2 up version number 3.0.0 -> 3.0.1 2026-04-18 10:37:03 -05:00
James Seibel 062ed5bcc8 remove dev from version number 2026-04-18 10:35:17 -05:00
James Seibel 539d152caa workaround for java 8 and forgix
Java 8 doesn't support "_" in the class name after "$". In other words inner classes can't have underscores in their names, which forgix adds for changed classes.

Moving the DhConfigScreen/ClassicConfigGUI into separate classes mitigates the problem until forgix has a long-term fix.
2026-04-18 09:44:37 -05:00
James Seibel a1af4335e0 fix buffer upload breaking UI on old MC versions 2026-04-17 07:49:04 -05:00
Ran-Mewo e68b112020 Forgix workaround 2026-04-17 00:14:28 +10:00
James Seibel fab6d187ca fix neoforge version range for mc 26 2026-04-15 21:51:17 -05:00
James Seibel 0daa00cec2 fix 26.1.2 version constant number 2026-04-15 21:51:02 -05:00
James Seibel f3036850ce Fix compiling for MC 1.19.4 and lower 2026-04-15 21:20:46 -05:00
James Seibel 51c8b47bba terrain data cash override close without exception 2026-04-15 07:47:02 -05:00
James Seibel 89efd53d61 fix unit test compiling 2026-04-14 20:38:19 -05:00
James Seibel 7667f51cf3 Add DhApiBlockColorOverrideEvent
Could be helpful to !1240
2026-04-14 20:36:34 -05:00
James Seibel 61eaa5a734 Add DhApiBlockStateWrapperCreatedEvent
Could be helpful to !1240
2026-04-14 19:44:24 -05:00
James Seibel 1d589d1a62 disable chat GL logging if Iris is detected 2026-04-14 19:03:43 -05:00
James Seibel 03b1eeb77e Add support for a couple render API events 2026-04-14 19:03:22 -05:00
James Seibel 8446df72f7 Merge branch 'change/channel_name_compat' 2026-04-14 17:08:45 -05:00
James Seibel c07397e9c0 update MC 26.1.0 -> 26.1.2 2026-04-14 17:05:16 -05:00
James Seibel 29a92aeb93 fix version constant 2026-04-14 07:48:58 -05:00
James Seibel 8467782b80 update unimined 1.4.17-k -> 1.4.18-k 2026-04-14 07:14:36 -05:00
James Seibel c8dbb21ea4 fix 6GB dev memory not working 2026-04-12 15:18:23 -05:00
James Seibel 63e1c12564 use down stream IBOs instead of re-creating at upload 2026-04-12 15:18:11 -05:00
James Seibel 52f58150da Fix MC crashing while triggering crashMinecraft() 2026-04-12 13:54:15 -05:00
James Seibel d1d642a7bb fix native dialog for MC 26 2026-04-12 13:53:52 -05:00
James Seibel 8e45358aad update buildall scripts to work with new forgix 2026-04-11 21:51:06 -05:00
James Seibel a959c7220b only run world gen for rendering levels 2026-04-11 21:41:07 -05:00
James Seibel e06425c5eb fix neo mixin chunk render preprocessors 2026-04-11 21:35:06 -05:00
James Seibel 66ce258fe1 fix biome/block wrapper preprocessors 2026-04-11 21:34:50 -05:00
James Seibel 181881a661 fix MC 1.17 compiling 2026-04-11 18:29:35 -05:00
James Seibel af0d8d1d2f add default MC memory 6gb command arg 2026-04-11 17:09:58 -05:00
James Seibel 6c68e94b96 Fix some compiling errors on old MC versions 2026-04-11 17:07:47 -05:00
James Seibel 93313a5c50 default to ZGC in dev environment 2026-04-11 17:01:57 -05:00
James Seibel 0527baa708 fix some old MC version compiling 2026-04-11 17:01:21 -05:00
James Seibel ce1fbde937 update gitlab URLs 2026-04-11 16:58:55 -05:00
James Seibel 764abdac45 add MC 26.1.2 to supported versions 2026-04-11 16:58:35 -05:00
James Seibel b42d3d8f74 remove Iris incompatibility and disable validation when present 2026-04-11 15:23:32 -05:00
James Seibel cd67a773c5 fix white beacons colored incorrectly 2026-04-11 12:34:14 -05:00
James Seibel 6d7bade7ca fix neoforge rendering on MC 26 2026-04-11 12:09:15 -05:00
James Seibel dea8d4498a fix double-rendering on fabric 2026-04-11 11:14:41 -05:00
James Seibel 2969916f34 minor optifine optimization 2026-04-11 11:11:56 -05:00
James Seibel 8785224c51 profile wrapper try-finally for pushes 2026-04-11 11:04:48 -05:00
James Seibel 605f02a655 fix compiling old MC versions 2026-04-11 09:22:14 -05:00
James Seibel 8099d37c14 add a comment for Iris 26 incompat reason 2026-04-11 09:19:44 -05:00
James Seibel dd4dbefe9a mark iris as incompatible with MC 26 2026-04-11 09:18:39 -05:00
James Seibel 52a15fd349 fix fading with sodium 2026-04-11 08:44:34 -05:00
James Seibel 3b3be6aed4 fix old MC compiling 2026-04-10 07:50:15 -05:00
James Seibel aeb7d6d0f9 update fabric api/iris references to latest versions 2026-04-10 07:47:19 -05:00
James Seibel 5336dbafec fix Intellij not debugging common classes 2026-04-10 07:21:45 -05:00
James Seibel 6079cb4830 minor mixin cleanup 2026-04-10 07:20:38 -05:00
James Seibel 50ff174104 Merge branch 'distant-horizons-view-bobbing' 2026-04-10 07:08:06 -05:00
James Seibel b77ef89df6 crash incomplete renderer in neo 2026-04-10 07:07:15 -05:00
James Seibel a701dd29a9 add 26.1.1 to supported version list 2026-04-10 07:07:01 -05:00
Brian McCoskey ab36fdd545 fix(1237): Updated LOD renderer for 26.1 to fix view bobbing issue described in issue #1237 2026-04-09 20:18:28 -04:00
James Seibel f87afb34f4 Rename MC 1.26.1 -> 26.1.0 2026-04-08 22:00:11 -05:00
James Seibel 053917d3d7 Fix compiling old MC versions 2026-04-08 21:53:37 -05:00
James Seibel 063ba01970 Fix tint color retrieval 2026-04-08 21:43:35 -05:00
James Seibel 72a888f3ff use more correct block color getting (thanks greener_ca) 2026-04-08 17:28:10 -05:00
James Seibel 0bd36bff1d re-add config UI validation 2026-04-08 17:27:44 -05:00
James Seibel 2bf125b7ac fix config button missing background 2026-04-08 17:27:33 -05:00
James Seibel ba3cf8fd56 up neoforge MC 26 version 1 -> 15 2026-04-08 07:46:24 -05:00
James Seibel 951f2a4ee7 add broken client block tinting 2026-04-08 07:45:41 -05:00
James Seibel d55b1bb3c2 default renderer to Blaze3D for MC 26 2026-04-08 07:45:26 -05:00
James Seibel 275ecb78c3 temporarily disable profiling
done due to bug with push/pop imbalance
2026-04-08 07:44:24 -05:00
James Seibel 64ac0d6017 Merge branch 'TheSecondGreatBuildscriptRewrite' 2026-04-08 07:41:00 -05:00
James Seibel 29381bce7b update manifold 25.1.31 -> 26.1.6 2026-03-30 18:05:26 -05:00
63 changed files with 3051 additions and 2420 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ build:
parallel: parallel:
matrix: matrix:
- MC_VER: [ - MC_VER: [
"1.26.1", "26.1.2",
"1.21.11", "1.21.10", "1.21.9", "1.21.8", "1.21.6", "1.21.5", "1.21.4", "1.21.3", "1.21.1", "1.21.11", "1.21.10", "1.21.9", "1.21.8", "1.21.6", "1.21.5", "1.21.4", "1.21.3", "1.21.1",
"1.20.6", "1.20.4", "1.20.2", "1.20.1", "1.20.6", "1.20.4", "1.20.2", "1.20.1",
"1.19.4", "1.19.2", "1.19.4", "1.19.2",
+20
View File
@@ -5,4 +5,24 @@ plugins {
forgix { forgix {
autoRun = true autoRun = true
// add the mod loaders to the end of the jar
// put together in the format: "a", "a-b", "a-b-c"
String modLoaders = "";
((String) gradle.builds_for)
.split(",")
.each
{ loader ->
def loaderName = loader.trim()
if (modLoaders != "")
{
modLoaders += "-";
}
modLoaders += loaderName;
}
// merged jars are named in the format:
// "DistantHorizons-3.0.1-b-dev-26.1-fabric-neoforge.jar"
archiveClassifier = modLoaders
} }
+2 -5
View File
@@ -3,6 +3,7 @@
echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ====================" echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ===================="
mkdir -p buildAllJars mkdir -p buildAllJars
rm -rf buildAllJars/* rm -rf buildAllJars/*
rm -rf build/forgix/*
# Loop trough everything in the version properties folder # Loop trough everything in the version properties folder
for d in versionProperties/*; do for d in versionProperties/*; do
@@ -19,10 +20,6 @@ for d in versionProperties/*; do
sh gradlew build -PmcVer=$version sh gradlew build -PmcVer=$version
if [ $? != 0 ]; then continue; fi if [ $? != 0 ]; then continue; fi
echo "==================== Merging $version ===================="
sh gradlew mergeJars -PmcVer=$version
if [ $? != 0 ]; then continue; fi
echo "==================== Moving jar ====================" echo "==================== Moving jar ===================="
mv build/merged/*.jar buildAllJars/ mv build/forgix/*.jar buildAllJars/
done done
+2 -4
View File
@@ -6,6 +6,7 @@
echo ==================== Note: All build jars will be in the folder called 'buildAllJars' ==================== echo ==================== Note: All build jars will be in the folder called 'buildAllJars' ====================
mkdir buildAllJars mkdir buildAllJars
del buildAllJars/* del buildAllJars/*
del build/forgix/*
@rem Loop trough everything in the version properties folder @rem Loop trough everything in the version properties folder
for %%f in (versionProperties\*) do ( for %%f in (versionProperties\*) do (
@@ -19,11 +20,8 @@ for %%f in (versionProperties\*) do (
echo ==================== Building !version! ==================== echo ==================== Building !version! ====================
call .\gradlew.bat build -PmcVer="!version!" call .\gradlew.bat build -PmcVer="!version!"
echo ==================== Merging !version! ====================
call .\gradlew.bat mergeJars -PmcVer="!version!"
echo ==================== Moving jar ==================== echo ==================== Moving jar ====================
move build\merged\*.jar buildAllJars\ move build\forgix\*.jar buildAllJars\
) )
endlocal endlocal
+1 -1
View File
@@ -18,7 +18,7 @@ repositories {
dependencies { dependencies {
implementation 'com.gradleup.shadow:shadow-gradle-plugin:9.0.0' implementation 'com.gradleup.shadow:shadow-gradle-plugin:9.0.0'
implementation 'xyz.wagyourtail.unimined:xyz.wagyourtail.unimined.gradle.plugin:1.4.17-kappa' implementation 'xyz.wagyourtail.unimined:xyz.wagyourtail.unimined.gradle.plugin:1.4.18-kappa'
implementation 'xyz.wagyourtail:manifold-gradle:1.0.0-SNAPSHOT' implementation 'xyz.wagyourtail:manifold-gradle:1.0.0-SNAPSHOT'
implementation 'xyz.wagyourtail.jvmdowngrader:xyz.wagyourtail.jvmdowngrader.gradle.plugin:1.3.4' implementation 'xyz.wagyourtail.jvmdowngrader:xyz.wagyourtail.jvmdowngrader.gradle.plugin:1.3.4'
} }
+26 -8
View File
@@ -286,7 +286,6 @@ class NativeTransformer implements ResourceTransformer {
if (isNotCommonProject) { if (isNotCommonProject) {
shadowJar { shadowJar {
configurations = [project.configurations.shadowMe] configurations = [project.configurations.shadowMe]
relocate "com.seibel.distanthorizons.common", "loaderCommon.${project.name}.com.seibel.distanthorizons.common"
def librariesLocation = "DistantHorizons.libraries" def librariesLocation = "DistantHorizons.libraries"
// LZ4 // LZ4
@@ -354,11 +353,23 @@ if (isNotCommonProject) {
def isClient = runTask.name.toLowerCase().contains("client") def isClient = runTask.name.toLowerCase().contains("client")
runTask.workingDir = rootProject.file("run/${isClient ? 'client' : 'server'}") runTask.workingDir = rootProject.file("run/${isClient ? 'client' : 'server'}")
// Minecraft automatically has G1GC args present,
// remove them so we can use ZGC instead
def filteredArgs = runTask.jvmArgs.findAll { arg ->
!arg.startsWith("-XX:+UseG1GC") &&
!arg.startsWith("-XX:G1") &&
!arg.startsWith("-XX:MaxGCPauseMillis")
}
runTask.jvmArgs = filteredArgs
// JVM args // JVM args
runTask.jvmArgs( runTask.jvmArgs(
"-Dio.netty.leakDetection.level=advanced", "-Dio.netty.leakDetection.level=advanced",
//"-XX:+UseZGC", // TODO only use for modern java versions
"-XX:+UseZGC",
// TODO don't use for even more modern-er java versions
//"-XX:+ZGenerational", //"-XX:+ZGenerational",
rootProject.minecraftMemoryJavaArg,
) )
if (isClient) { if (isClient) {
runTask.jvmArgs( runTask.jvmArgs(
@@ -367,7 +378,13 @@ if (isNotCommonProject) {
"-Dminecraft.api.session.host=https://nope.invalid", "-Dminecraft.api.session.host=https://nope.invalid",
"-Dminecraft.api.services.host=https://nope.invalid", "-Dminecraft.api.services.host=https://nope.invalid",
) )
runTask.args("--username", "Dev", "--renderDebugLabels", "--tracy") runTask.args(
// use a consistent username for easier debugging in a given world (vs randomly teleporting to a new user each time the game boots)
"--username", "Dev",
// "--renderDebugLabels" is a Mojang command to show render names in RenderDoc
"--renderDebugLabels",
// "--tracy" is a Mojang command to allow individual frames to be debugged using Tracy https://github.com/wolfpld/tracy/releases/tag/v0.13.1
"--tracy")
} }
} }
} }
@@ -417,6 +434,7 @@ if (isNotCommonProject) {
issues : rootProject.mod_issues, issues : rootProject.mod_issues,
discord : rootProject.mod_discord, discord : rootProject.mod_discord,
minecraft_version : rootProject.minecraft_version, minecraft_version : rootProject.minecraft_version,
accessWidenerVersion : rootProject.accessWidenerVersion,
compatible_minecraft_versions: rootProject.compatible_minecraft_versions, compatible_minecraft_versions: rootProject.compatible_minecraft_versions,
compatible_forgemc_versions : compatible_forgemc_versions, compatible_forgemc_versions : compatible_forgemc_versions,
java_version : rootProject.java_version, java_version : rootProject.java_version,
@@ -447,11 +465,11 @@ if (isNotCommonProject) {
// ==================== Resource Copy Tasks ==================== // ==================== Resource Copy Tasks ====================
task copyCommonLoaderResources(type: Copy) { // task copyCommonLoaderResources(type: Copy) {
from project(":common").file("src/main/resources/${rootProject.accessWidenerVersion}.distanthorizons.accesswidener") // from project(":common").file("src/main/resources/${rootProject.accessWidenerVersion}.distanthorizons.accesswidener")
into(file(project.file("build/resources/main"))) // into(file(project.file("build/resources/main")))
rename "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener" // rename "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
} // }
task copyCoreResources(type: Copy) { task copyCoreResources(type: Copy) {
from fileTree(project(":core").file("src/main/resources")) from fileTree(project(":core").file("src/main/resources"))
@@ -21,10 +21,8 @@ import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer; import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.render.renderer.StubDebugWireframeRenderer; import com.seibel.distanthorizons.core.render.renderer.StubDebugWireframeRenderer;
import com.seibel.distanthorizons.core.util.NativeDialogUtil; import com.seibel.distanthorizons.common.wrappers.gui.NativeDialogUtil;
import com.seibel.distanthorizons.core.util.ThreadUtil; import com.seibel.distanthorizons.core.util.ThreadUtil;
import com.seibel.distanthorizons.core.util.threading.DhThreadFactory;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants; import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
@@ -375,10 +373,10 @@ public abstract class AbstractModInitializer
renderApi = versionConstants.getDefaultRenderingApi(); renderApi = versionConstants.getDefaultRenderingApi();
} }
// Iris only supports nataive OpenGL // Iris only supports native OpenGL
if (renderApi != EDhApiRenderApi.OPEN_GL) if (renderApi != EDhApiRenderApi.OPEN_GL)
{ {
String irisUnsupportedMessage = "Iris doesn't support DH when using the ["+EDhApiRenderApi.BLAZE_3D+"] rendering API, this will need to be fixed on Iris' end. As a temporary fix please change the rendering API to ["+EDhApiRenderApi.OPEN_GL+"] in DH's config file."; String irisUnsupportedMessage = "Iris doesn't support DH when using the ["+EDhApiRenderApi.BLAZE_3D+"] rendering API, this will need to be fixed on Iris end. As a temporary fix please change the rendering API to ["+EDhApiRenderApi.OPEN_GL+"] in the DH config file.";
LOGGER.fatal(irisUnsupportedMessage); LOGGER.fatal(irisUnsupportedMessage);
NativeDialogUtil.showDialog(ModInfo.READABLE_NAME, irisUnsupportedMessage, "ok", "error"); NativeDialogUtil.showDialog(ModInfo.READABLE_NAME, irisUnsupportedMessage, "ok", "error");
@@ -330,194 +330,194 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
@Override @Override
public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao) public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao)
{ {
//==============//
// render setup //
//==============//
//#region
profiler.push("setup"); try (IProfilerWrapper.IProfileBlock generic_profile = profiler.push("setup"))
this.init();
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
Vec3d camPos = MC_RENDER.getCameraExactPosition();
//#endregion
if (BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty())
{ {
return;
}
//==============//
// render setup //
//==============//
//#region
//===========// this.init();
// rendering //
//===========//
//#region
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values(); ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
for (RenderableBoxGroup boxGroup : boxList)
{
// validation //
// shouldn't happen, but just in case Vec3d camPos = MC_RENDER.getCameraExactPosition();
if (boxGroup == null)
//#endregion
if (BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty())
{ {
continue; return;
} }
// skip boxes that shouldn't render this pass
if (boxGroup.ssaoEnabled != renderingWithSsao)
//===========//
// rendering //
//===========//
//#region
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
for (RenderableBoxGroup boxGroup : boxList)
{ {
continue; // validation //
}
profiler.popPush("render prep"); // shouldn't happen, but just in case
boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired if (boxGroup == null)
// ignore inactive groups
if (!boxGroup.active)
{
continue;
}
// allow API users to cancel this object's rendering
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
if (cancelRendering)
{
continue;
}
// update instanced data if needed
{
boxGroup.tryUpdateInstancedDataAsync();
// skip groups that haven't been uploaded yet
if (boxGroup.vertexBufferContainer.getState() != IDhGenericObjectVertexBufferContainer.EState.RENDER)
{ {
continue; continue;
} }
// skip boxes that shouldn't render this pass
if (boxGroup.ssaoEnabled != renderingWithSsao)
{
continue;
}
profiler.popPush("render prep");
boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired
// ignore inactive groups
if (!boxGroup.active)
{
continue;
}
// allow API users to cancel this object's rendering
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
if (cancelRendering)
{
continue;
}
// update instanced data if needed
{
boxGroup.tryUpdateInstancedDataAsync();
// skip groups that haven't been uploaded yet
if (boxGroup.vertexBufferContainer.getState() != IDhGenericObjectVertexBufferContainer.EState.RENDER)
{
continue;
}
}
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
if (shading == null)
{
shading = DEFAULT_SHADING;
}
// uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putIVec3() // uOffsetChunk
.putVec3() // uOffsetSubChunk
.putIVec3() // uCameraPosChunk
.putVec3() // uCameraPosSubChunk
.putVec3() // aTranslateChunk
.putVec3() // aTranslateSubChunk
.putMat4f() // uProjectionMvm
.putInt() // uSkyLight
.putInt() // uBlockLight
.putFloat() // uNorthShading
.putFloat() // uSouthShading
.putFloat() // uEastShading
.putFloat() // uWestShading
.putFloat() // uTopShading
.putFloat() // uBottomShading
.get();
// create data //
Mat4f projectionMvmMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
projectionMvmMatrix.multiply(renderEventParam.dhModelViewMatrix);
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putIVec3(
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
) // uOffsetChunk
.putVec3(
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
) // uOffsetSubChunk
.putIVec3(
LodUtil.getChunkPosFromDouble(camPos.x),
LodUtil.getChunkPosFromDouble(camPos.y),
LodUtil.getChunkPosFromDouble(camPos.z)
) // uCameraPosChunk
.putVec3(
LodUtil.getSubChunkPosFromDouble(camPos.x),
LodUtil.getSubChunkPosFromDouble(camPos.y),
LodUtil.getSubChunkPosFromDouble(camPos.z)
) // uCameraPosSubChunk
.putMat4f(projectionMvmMatrix.createJomlMatrix()) // uProjectionMvm
.putInt(boxGroup.getSkyLight()) // uSkyLight
.putInt(boxGroup.getBlockLight()) // uBlockLight
.putFloat(shading.north)
.putFloat(shading.south)
.putFloat(shading.east)
.putFloat(shading.west)
.putFloat(shading.top)
.putFloat(shading.bottom)
.get()
;
this.vertUniformBuffer = BlazeUniformUtil.createBuffer("vertUniformBlock", uniformBufferSize, this.vertUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
// render //
profiler.popPush("rendering");
try (IProfilerWrapper.IProfileBlock namespace_profile = profiler.push(boxGroup.getResourceLocationNamespace());
IProfilerWrapper.IProfileBlock location_profile = profiler.push(boxGroup.getResourceLocationPath()))
{
this.renderBoxGroupInstanced(renderEventParam, boxGroup, profiler);
}
boxGroup.postRender(renderEventParam);
} }
//#endregion
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
if (shading == null)
{
shading = DEFAULT_SHADING;
}
// uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putIVec3() // uOffsetChunk
.putVec3() // uOffsetSubChunk
.putIVec3() // uCameraPosChunk
.putVec3() // uCameraPosSubChunk
.putVec3() // aTranslateChunk
.putVec3() // aTranslateSubChunk
.putMat4f() // uProjectionMvm
.putInt() // uSkyLight
.putInt() // uBlockLight
.putFloat() // uNorthShading
.putFloat() // uSouthShading
.putFloat() // uEastShading
.putFloat() // uWestShading
.putFloat() // uTopShading
.putFloat() // uBottomShading
.get();
// create data //
Mat4f projectionMvmMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
projectionMvmMatrix.multiply(renderEventParam.dhModelViewMatrix);
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putIVec3(
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
) // uOffsetChunk
.putVec3(
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
) // uOffsetSubChunk
.putIVec3(
LodUtil.getChunkPosFromDouble(camPos.x),
LodUtil.getChunkPosFromDouble(camPos.y),
LodUtil.getChunkPosFromDouble(camPos.z)
) // uCameraPosChunk
.putVec3(
LodUtil.getSubChunkPosFromDouble(camPos.x),
LodUtil.getSubChunkPosFromDouble(camPos.y),
LodUtil.getSubChunkPosFromDouble(camPos.z)
) // uCameraPosSubChunk
.putMat4f(projectionMvmMatrix.createJomlMatrix()) // uProjectionMvm
.putInt(boxGroup.getSkyLight()) // uSkyLight
.putInt(boxGroup.getBlockLight()) // uBlockLight
.putFloat(shading.north)
.putFloat(shading.south)
.putFloat(shading.east)
.putFloat(shading.west)
.putFloat(shading.top)
.putFloat(shading.bottom)
.get()
;
this.vertUniformBuffer = BlazeUniformUtil.createBuffer("vertUniformBlock", uniformBufferSize, this.vertUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
//==========//
// clean up //
//==========//
//region
// render // profiler.popPush("cleanup");
profiler.popPush("rendering"); ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
profiler.push(boxGroup.getResourceLocationNamespace());
profiler.push(boxGroup.getResourceLocationPath());
this.renderBoxGroupInstanced(renderEventParam, boxGroup, profiler); //endregion
profiler.pop(); // resource path
profiler.pop(); // resource namespace
boxGroup.postRender(renderEventParam);
} }
//#endregion
//==========//
// clean up //
//==========//
//region
profiler.popPush("cleanup");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
profiler.pop();
//endregion
} }
private String getRenderPassName() { return "distantHorizons:McGenericObjectRenderer"; } private String getRenderPassName() { return "distantHorizons:McGenericObjectRenderer"; }
@@ -545,8 +545,6 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
// update instance data // // update instance data //
profiler.push("vertex setup");
BlazeGenericObjectVertexContainer container = (BlazeGenericObjectVertexContainer) boxGroup.vertexBufferContainer; BlazeGenericObjectVertexContainer container = (BlazeGenericObjectVertexContainer) boxGroup.vertexBufferContainer;
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap; LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
@@ -556,7 +554,6 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
// Bind instance data // // Bind instance data //
profiler.popPush("binding");
renderPass.setUniform("vertUniformBlock", this.vertUniformBuffer); renderPass.setUniform("vertUniformBlock", this.vertUniformBuffer);
@@ -568,7 +565,6 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
renderPass.setVertexBuffer(0, container.vboGpuBuffer); renderPass.setVertexBuffer(0, container.vboGpuBuffer);
// Draw instanced // Draw instanced
profiler.popPush("render");
if (container.uploadedBoxCount > 0) if (container.uploadedBoxCount > 0)
{ {
renderPass.drawIndexed( renderPass.drawIndexed(
@@ -579,7 +575,6 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
} }
} }
profiler.pop();
} }
//endregion //endregion
@@ -6,13 +6,16 @@ public class BlazeDhMetaRenderer {}
#else #else
import com.mojang.blaze3d.textures.GpuTexture; import com.mojang.blaze3d.textures.GpuTexture;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterColorDepthTextureCreatedEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiTextureCreatedParam;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer; import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper; import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.RenderParams; import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer; import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import java.awt.*; import java.awt.*;
@@ -57,9 +60,24 @@ public class BlazeDhMetaRenderer implements IDhMetaRenderer
@Override @Override
public void runRenderPassSetup(RenderParams renderParams) public void runRenderPassSetup(RenderParams renderParams)
{ {
// textures int oldWidth = this.dhDepthTextureWrapper.getWidth();
this.dhDepthTextureWrapper.tryCreateOrResize(); int oldHeight = this.dhDepthTextureWrapper.getHeight();
this.dhColorTextureWrapper.tryCreateOrResize();
boolean texturesChanged = false;
texturesChanged = this.dhDepthTextureWrapper.tryCreateOrResize() | texturesChanged;
texturesChanged = this.dhColorTextureWrapper.tryCreateOrResize() | texturesChanged;
if (texturesChanged)
{
int newTextureWidth = MC_RENDER.getTargetFramebufferViewportWidth();
int newTextureHeight = MC_RENDER.getTargetFramebufferViewportHeight();
DhApiTextureCreatedParam textureCreatedParam = new DhApiTextureCreatedParam(
oldWidth, oldHeight,
newTextureWidth, newTextureHeight
);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterColorDepthTextureCreatedEvent.class, textureCreatedParam);
}
} }
@Override @Override
@@ -151,210 +151,206 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
{ {
this.tryInit(); this.tryInit();
try(IProfilerWrapper.IProfileBlock terrain_profile = profiler.push("terrain render"))
profiler.push("vert unique uniforms");
{ {
// create data // profiler.popPush("vert unique uniforms");
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{ {
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex); // create data //
bufferContainer.uniformContainer.tryUpload();
}
}
profiler.popPush("vert share uniforms");
{
Mat4f combinedMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
combinedMatrix.multiply(renderEventParam.dhModelViewMatrix);
float earthCurveRatio = Config.Client.Advanced.Graphics.Experimental.earthCurveRatio.get();
if (earthCurveRatio < -1.0f || earthCurveRatio > 1.0f)
{
earthCurveRatio = /*6371KM*/ 6371000.0f / earthCurveRatio;
}
else
{
// disable curvature if the config value is between -1 and 1
earthCurveRatio = 0.0f;
}
// upload data //
int uniformBufferSize = new Std140SizeCalculator()
.putInt() // uIsWhiteWorld
.putFloat() // uWorldYOffset
.putFloat() // uMircoOffset
.putFloat() // uEarthRadius
.putVec3() // uCameraPos
.putMat4f() // uCombinedMatrix
.get();
ByteBuffer buffer = MemoryUtil.memAlloc(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
Std140Builder.intoBuffer(buffer)
.putInt(0) // uIsWhiteWorld
.putFloat((float) renderEventParam.worldYOffset) // uWorldYOffset
.putFloat(0.01f) // uMircoOffset // 0.01 block offset
.putFloat(earthCurveRatio) // uEarthRadius
.putVec3(
(float)renderEventParam.exactCameraPosition.x,
(float)renderEventParam.exactCameraPosition.y,
(float)renderEventParam.exactCameraPosition.z) // uCameraPos
.putMat4f(combinedMatrix.createJomlMatrix()) // uCombinedMatrix
.get();
this.vertSharedUniformBuffer = BlazeUniformUtil.createBuffer("vertSharedUniformBlock", uniformBufferSize, this.vertSharedUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertSharedUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
MemoryUtil.memFree(buffer);
}
profiler.popPush("set frag uniforms");
{
int uniformBufferSize = new Std140SizeCalculator()
.putFloat() // uClipDistance
.putFloat() // uNoiseIntensity
.putInt() // uNoiseSteps
.putInt() // uNoiseDropoff
.putInt() // uDitherDhRendering
.putInt() // uNoiseEnabled
.get();
// create data //
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
if (!Config.Client.Advanced.Debugging.lodOnlyMode.get())
{
// this added value prevents the near clip plane and discard circle from touching, which looks bad
dhNearClipDistance += 16f;
}
// upload data //
ByteBuffer buffer = MemoryUtil.memAlloc(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putFloat(dhNearClipDistance) // uClipDistance
.putFloat(Config.Client.Advanced.Graphics.NoiseTexture.noiseIntensity.get()) // uNoiseIntensity
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.noiseSteps.get()) // uNoiseSteps
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.noiseDropoff.get()) // uNoiseDropoff
.putInt(Config.Client.Advanced.Graphics.Quality.ditherDhFade.get() ? 1 : 0) // uDitherDhRendering
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.enableNoiseTexture.get() ? 1 : 0) // uNoiseEnabled
.get()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
MemoryUtil.memFree(buffer);
}
// render pass setup
{
profiler.popPush("setup");
// create a render pass
try(RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty())
)
{
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
renderPass.bindTexture("uLightMap", lightmapTextureViewWrapper.textureView, lightmapTextureViewWrapper.textureSampler);
// set pipeline
renderPass.setPipeline(opaquePass ? this.opaquePipeline : this.transparentPipeline);
// shared uniforms
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setUniform("vertSharedUniformBlock", this.vertSharedUniformBuffer);
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++) for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{ {
profiler.popPush("binding");
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex); LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
BlazeLodUniformBufferWrapper uniformWrapper = (BlazeLodUniformBufferWrapper)bufferContainer.uniformContainer; bufferContainer.uniformContainer.tryUpload();
}
}
boolean columnBuilderDebugEnabled = Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugEnable.get(); profiler.popPush("vert share uniforms");
if (columnBuilderDebugEnabled) {
{ Mat4f combinedMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
if (DhSectionPos.getDetailLevel(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugDetailLevel.get() combinedMatrix.multiply(renderEventParam.dhModelViewMatrix);
&& DhSectionPos.getX(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugXPos.get()
&& DhSectionPos.getZ(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugZPos.get())
{
int breakpoint = 0;
}
else
{
continue;
}
}
renderPass.setUniform("vertUniqueUniformBlock", uniformWrapper.gpuBuffer); float earthCurveRatio = Config.Client.Advanced.Graphics.Experimental.earthCurveRatio.get();
if (earthCurveRatio < -1.0f || earthCurveRatio > 1.0f)
{
earthCurveRatio = /*6371KM*/ 6371000.0f / earthCurveRatio;
profiler.popPush("rendering"); }
else
// render each buffer {
IVertexBufferWrapper[] bufferWrapperList = opaquePass ? bufferContainer.vboOpaqueWrappers : bufferContainer.vboTransparentWrappers; // disable curvature if the config value is between -1 and 1
for (int i = 0; i < bufferWrapperList.length; i++) earthCurveRatio = 0.0f;
{
BlazeVertexBufferWrapper bufferWrapper = (BlazeVertexBufferWrapper) bufferWrapperList[i];
if (!bufferWrapper.uploaded
|| bufferWrapper.vertexCount == 0)
{
continue;
}
// fire render event
{
Vec3d camPos = renderEventParam.exactCameraPosition;
Vec3f modelPos = new Vec3f(
(float) (bufferContainer.minCornerBlockPos.getX() - camPos.x),
(float) (bufferContainer.minCornerBlockPos.getY() - camPos.y),
(float) (bufferContainer.minCornerBlockPos.getZ() - camPos.z));
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, new DhApiBeforeBufferRenderEvent.EventParam(renderEventParam, modelPos));
}
renderPass.setIndexBuffer(bufferWrapper.getIndexGpuBuffer(), VertexFormat.IndexType.INT);
renderPass.setVertexBuffer(0, bufferWrapper.vertexGpuBuffer); // vertex buffer can only be "0" lol
if (!bufferWrapper.vertexGpuBuffer.isClosed())
{
renderPass.drawIndexed(
/*indexStart*/ 0,
/*firstIndex*/0,
/*indexCount*/bufferWrapper.indexCount,
/*instanceCount*/1);
}
}
} }
// upload data //
int uniformBufferSize = new Std140SizeCalculator()
.putInt() // uIsWhiteWorld
.putFloat() // uWorldYOffset
.putFloat() // uMircoOffset
.putFloat() // uEarthRadius
.putVec3() // uCameraPos
.putMat4f() // uCombinedMatrix
.get();
ByteBuffer buffer = MemoryUtil.memAlloc(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
Std140Builder.intoBuffer(buffer)
.putInt(0) // uIsWhiteWorld
.putFloat((float) renderEventParam.worldYOffset) // uWorldYOffset
.putFloat(0.01f) // uMircoOffset // 0.01 block offset
.putFloat(earthCurveRatio) // uEarthRadius
.putVec3(
(float) renderEventParam.exactCameraPosition.x,
(float) renderEventParam.exactCameraPosition.y,
(float) renderEventParam.exactCameraPosition.z) // uCameraPos
.putMat4f(combinedMatrix.createJomlMatrix()) // uCombinedMatrix
.get();
this.vertSharedUniformBuffer = BlazeUniformUtil.createBuffer("vertSharedUniformBlock", uniformBufferSize, this.vertSharedUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertSharedUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
MemoryUtil.memFree(buffer);
}
profiler.popPush("set frag uniforms");
{
int uniformBufferSize = new Std140SizeCalculator()
.putFloat() // uClipDistance
.putFloat() // uNoiseIntensity
.putInt() // uNoiseSteps
.putInt() // uNoiseDropoff
.putInt() // uDitherDhRendering
.putInt() // uNoiseEnabled
.get();
// create data //
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
if (!Config.Client.Advanced.Debugging.lodOnlyMode.get())
{
// this added value prevents the near clip plane and discard circle from touching, which looks bad
dhNearClipDistance += 16f;
}
// upload data //
ByteBuffer buffer = MemoryUtil.memAlloc(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putFloat(dhNearClipDistance) // uClipDistance
.putFloat(Config.Client.Advanced.Graphics.NoiseTexture.noiseIntensity.get()) // uNoiseIntensity
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.noiseSteps.get()) // uNoiseSteps
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.noiseDropoff.get()) // uNoiseDropoff
.putInt(Config.Client.Advanced.Graphics.Quality.ditherDhFade.get() ? 1 : 0) // uDitherDhRendering
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.enableNoiseTexture.get() ? 1 : 0) // uNoiseEnabled
.get()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
MemoryUtil.memFree(buffer);
}
// render pass setup
{
profiler.popPush("rendering");
// create a render pass
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty())
)
{
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
renderPass.bindTexture("uLightMap", lightmapTextureViewWrapper.textureView, lightmapTextureViewWrapper.textureSampler);
// set pipeline
renderPass.setPipeline(opaquePass ? this.opaquePipeline : this.transparentPipeline);
// shared uniforms
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setUniform("vertSharedUniformBlock", this.vertSharedUniformBuffer);
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
BlazeLodUniformBufferWrapper uniformWrapper = (BlazeLodUniformBufferWrapper) bufferContainer.uniformContainer;
boolean columnBuilderDebugEnabled = Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugEnable.get();
if (columnBuilderDebugEnabled)
{
if (DhSectionPos.getDetailLevel(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugDetailLevel.get()
&& DhSectionPos.getX(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugXPos.get()
&& DhSectionPos.getZ(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugZPos.get())
{
int breakpoint = 0;
}
else
{
continue;
}
}
renderPass.setUniform("vertUniqueUniformBlock", uniformWrapper.gpuBuffer);
// render each buffer
IVertexBufferWrapper[] bufferWrapperList = opaquePass ? bufferContainer.vboOpaqueWrappers : bufferContainer.vboTransparentWrappers;
for (int i = 0; i < bufferWrapperList.length; i++)
{
BlazeVertexBufferWrapper bufferWrapper = (BlazeVertexBufferWrapper) bufferWrapperList[i];
if (!bufferWrapper.uploaded
|| bufferWrapper.vertexCount == 0)
{
continue;
}
// fire render event
{
Vec3d camPos = renderEventParam.exactCameraPosition;
Vec3f modelPos = new Vec3f(
(float) (bufferContainer.minCornerBlockPos.getX() - camPos.x),
(float) (bufferContainer.minCornerBlockPos.getY() - camPos.y),
(float) (bufferContainer.minCornerBlockPos.getZ() - camPos.z));
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, new DhApiBeforeBufferRenderEvent.EventParam(renderEventParam, modelPos));
}
renderPass.setIndexBuffer(bufferWrapper.getIndexGpuBuffer(), VertexFormat.IndexType.INT);
renderPass.setVertexBuffer(0, bufferWrapper.vertexGpuBuffer); // vertex buffer can only be "0" lol
if (!bufferWrapper.vertexGpuBuffer.isClosed())
{
renderPass.drawIndexed(
/*indexStart*/ 0,
/*firstIndex*/0,
/*indexCount*/bufferWrapper.indexCount,
/*instanceCount*/1);
}
}
}
}
} }
} }
profiler.pop();
} }
private String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; } private String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
private String getRenderPassName() { return "distantHorizons:McLodRenderer"; } private String getRenderPassName() { return "distantHorizons:McLodRenderer"; }
@@ -17,7 +17,7 @@ import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler; import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer; import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup; import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import org.lwjgl.opengl.GL32; import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -1,15 +1,26 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers; package com.seibel.distanthorizons.common.render.blaze.wrappers;
#if MC_VER <= MC_1_21_10
public class RenderPipelineBuilderWrapper {}
#else
import com.mojang.blaze3d.pipeline.BlendFunction; import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.ColorTargetState;
import com.mojang.blaze3d.pipeline.DepthStencilState;
import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.CompareOp;
import com.mojang.blaze3d.platform.PolygonMode; import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType; import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.resources.Identifier; import net.minecraft.resources.Identifier;
#if MC_VER <= MC_1_21_11
import com.mojang.blaze3d.platform.DepthTestFunction;
#else
import com.mojang.blaze3d.pipeline.ColorTargetState;
import com.mojang.blaze3d.pipeline.DepthStencilState;
import com.mojang.blaze3d.platform.CompareOp;
#endif
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Optional; import java.util.Optional;
@@ -206,15 +217,20 @@ public class RenderPipelineBuilderWrapper
this.blazePipelineBuilder.withoutBlend(); this.blazePipelineBuilder.withoutBlend();
} }
DepthTestFunction depthTestFunction;
switch (this.depthTest) switch (this.depthTest)
{ {
case NONE: case NONE:
depthTestFunction = DepthTestFunction.NO_DEPTH_TEST;
break; break;
case LESS: case LESS:
depthTestFunction = DepthTestFunction.LESS_DEPTH_TEST;
break; break;
default:
throw new UnsupportedOperationException("No depth test defined for type ["+this.depthTest+"].");
} }
this.blazepipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE); this.blazePipelineBuilder.withDepthTestFunction(depthTestFunction);
#else #else
@@ -349,3 +365,4 @@ public class RenderPipelineBuilderWrapper
} }
#endif
@@ -140,7 +140,7 @@ public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
} }
@Override @Override
public void uploadIndexBuffer(ByteBuffer buffer, int vertexCount) public void uploadIndexBuffer(ByteBuffer indexBuffer, int vertexCount)
{ {
int oldIndexCount = this.indexCount; int oldIndexCount = this.indexCount;
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5 // 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
@@ -169,17 +169,12 @@ public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
this.indexGpuBuffer.close(); this.indexGpuBuffer.close();
} }
ByteBuffer indexBuffer = IndexBufferBuilder.createBuffer(this.vertexCount);
int usage = GpuBuffer.USAGE_COPY_DST int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_INDEX; | GpuBuffer.USAGE_INDEX;
this.indexGpuBuffer = GPU_DEVICE.createBuffer(BlazeVertexBufferWrapper::getIndexBufferName, usage, indexBuffer.capacity()); this.indexGpuBuffer = GPU_DEVICE.createBuffer(BlazeVertexBufferWrapper::getIndexBufferName, usage, indexBuffer.capacity());
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, /*offset*/ 0, indexBuffer.capacity()); GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, /*offset*/ 0, indexBuffer.capacity());
COMMAND_ENCODER.writeToBuffer(bufferSlice, indexBuffer); COMMAND_ENCODER.writeToBuffer(bufferSlice, indexBuffer);
MemoryUtil.memFree(indexBuffer);
} }
} }
private static String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; } private static String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
@@ -13,7 +13,7 @@ import com.mojang.blaze3d.textures.*;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import java.util.OptionalDouble; import java.util.OptionalDouble;
@@ -79,42 +79,52 @@ public class BlazeTextureWrapper
//=======// //=======//
//region //region
/** does nothing if the texture is already created and the correct size */ /**
public void tryCreateOrResize() * does nothing if the texture is already created and the correct size
* @return true if the texture was (re)created
*/
public boolean tryCreateOrResize()
{ {
this.tryCreateTexture(); boolean textureChanged = this.tryCreateTexture();
this.tryCreateSampler(); this.tryCreateSampler();
return textureChanged;
} }
private void tryCreateTexture() private boolean tryCreateTexture()
{ {
int viewWidth = MC_RENDER.getTargetFramebufferViewportWidth(); int viewWidth = MC_RENDER.getTargetFramebufferViewportWidth();
int viewHeight = MC_RENDER.getTargetFramebufferViewportHeight(); int viewHeight = MC_RENDER.getTargetFramebufferViewportHeight();
if (this.texture == null if (this.texture != null
|| this.width != viewWidth && this.width == viewWidth
|| this.height != viewHeight) && this.height == viewHeight)
{ {
if (this.texture != null) // no changes needed
{ return false;
this.texture.close();
this.textureView.close();
}
this.width = viewWidth;
this.height = viewHeight;
int usage = GpuTexture.USAGE_COPY_DST
| GpuTexture.USAGE_TEXTURE_BINDING
| GpuTexture.USAGE_COPY_SRC
| GpuTexture.USAGE_RENDER_ATTACHMENT;
this.texture = GPU_DEVICE.createTexture(this.name,
usage,
this.textureFormat,
viewWidth, viewHeight,
/*depthOrLayers*/ 1, /*mipLevels*/ 1
);
this.textureView = GPU_DEVICE.createTextureView(this.texture);
} }
if (this.texture != null)
{
this.texture.close();
this.textureView.close();
}
this.width = viewWidth;
this.height = viewHeight;
int usage = GpuTexture.USAGE_COPY_DST
| GpuTexture.USAGE_TEXTURE_BINDING
| GpuTexture.USAGE_COPY_SRC
| GpuTexture.USAGE_RENDER_ATTACHMENT;
this.texture = GPU_DEVICE.createTexture(this.name,
usage,
this.textureFormat,
viewWidth, viewHeight,
/*depthOrLayers*/ 1, /*mipLevels*/ 1
);
this.textureView = GPU_DEVICE.createTextureView(this.texture);
return true;
} }
private void tryCreateSampler() private void tryCreateSampler()
{ {
@@ -14,6 +14,7 @@ import com.seibel.distanthorizons.common.render.openGl.terrain.GlDhTerrainShader
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper; import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -22,6 +23,7 @@ import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer; import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector; import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
@@ -45,6 +47,8 @@ public class GlDhMetaRenderer implements IDhMetaRenderer
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE; private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
private int activeFramebufferId = -1; private int activeFramebufferId = -1;
private int activeColorTextureId = -1; private int activeColorTextureId = -1;
@@ -242,7 +246,7 @@ public class GlDhMetaRenderer implements IDhMetaRenderer
// create or get the frame buffer // create or get the frame buffer
if (AbstractOptifineAccessor.optifinePresent()) if (OPTIFINE_ACCESSOR != null)
{ {
// use MC/Optifine's default Framebuffer so shaders won't remove the LODs // use MC/Optifine's default Framebuffer so shaders won't remove the LODs
int currentFramebufferId = MC_RENDER.getTargetFramebuffer(); int currentFramebufferId = MC_RENDER.getTargetFramebuffer();
@@ -383,31 +387,26 @@ public class GlDhMetaRenderer implements IDhMetaRenderer
// needs to be fired after all the textures have been created/bound GL32.glClearDepth(1.0);
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderParams);
if (clearTextures) float[] clearColorValues = new float[4];
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 1.0f);
if (this.usingMcFramebuffer
&& framebufferOverride == null)
{ {
GL32.glClearDepth(1.0); //// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
//// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
float[] clearColorValues = new float[4]; //this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 1.0f);
if (this.usingMcFramebuffer
&& framebufferOverride == null)
{
//// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
//// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
//this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
// don't clear the color texture, that removes the sky // don't clear the color texture, that removes the sky
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT); GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
} }
else if (firstPass) else if (firstPass)
{ {
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT); GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
}
} }
} }
@@ -413,133 +413,133 @@ public class GlGenericObjectRenderer implements IDhGenericRenderer
// render setup // // render setup //
profiler.push("setup"); try (IProfilerWrapper.IProfileBlock setup_profile = profiler.push("setup"))
this.init();
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get();
if (renderWireframe)
{ {
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
GLMC.disableFaceCulling();
}
else
{
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GLMC.enableFaceCulling();
}
GLMC.enableBlend(); this.init();
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
IDhApiGenericObjectShaderProgram shaderProgram = this.instancedRenderingAvailable ? this.instancedShaderProgram : this.directShaderProgram; ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
IDhApiGenericObjectShaderProgram shaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiGenericObjectShaderProgram.class);
if (shaderProgramOverride != null && shaderProgram.overrideThisFrame())
{
shaderProgram = shaderProgramOverride;
}
shaderProgram.bind(renderEventParam);
shaderProgram.bindVertexBuffer(this.boxVertexBuffer.getId());
this.boxIndexBuffer.bind();
Vec3d camPos = MC_RENDER.getCameraExactPosition();
boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get();
// rendering // if (renderWireframe)
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
for (RenderableBoxGroup boxGroup : boxList)
{
// validation //
// shouldn't happen, but just in case
if (boxGroup == null)
{ {
continue; GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
} GLMC.disableFaceCulling();
// skip boxes that shouldn't render this pass
if (boxGroup.ssaoEnabled != renderingWithSsao)
{
continue;
}
profiler.popPush("render prep");
boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired
// ignore inactive groups
if (!boxGroup.active)
{
continue;
}
// allow API users to cancel this object's rendering
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
if (cancelRendering)
{
continue;
}
// update instanced data if needed
if (this.instancedRenderingAvailable)
{
boxGroup.tryUpdateInstancedDataAsync();
// skip groups that haven't been uploaded yet
if (boxGroup.vertexBufferContainer.getState() != GlGenericObjectVertexContainer.EState.RENDER)
{
continue;
}
}
// render //
profiler.popPush("rendering");
profiler.push(boxGroup.getResourceLocationNamespace());
profiler.push(boxGroup.getResourceLocationPath());
if (this.instancedRenderingAvailable)
{
this.renderBoxGroupInstanced(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
} }
else else
{ {
this.renderBoxGroupDirect(shaderProgram, renderEventParam, boxGroup, camPos, profiler); GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GLMC.enableFaceCulling();
} }
profiler.pop(); // resource path
profiler.pop(); // resource namespace
boxGroup.postRender(renderEventParam); GLMC.enableBlend();
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
IDhApiGenericObjectShaderProgram shaderProgram = this.instancedRenderingAvailable ? this.instancedShaderProgram : this.directShaderProgram;
IDhApiGenericObjectShaderProgram shaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiGenericObjectShaderProgram.class);
if (shaderProgramOverride != null && shaderProgram.overrideThisFrame())
{
shaderProgram = shaderProgramOverride;
}
shaderProgram.bind(renderEventParam);
shaderProgram.bindVertexBuffer(this.boxVertexBuffer.getId());
this.boxIndexBuffer.bind();
Vec3d camPos = MC_RENDER.getCameraExactPosition();
// rendering //
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
for (RenderableBoxGroup boxGroup : boxList)
{
// validation //
// shouldn't happen, but just in case
if (boxGroup == null)
{
continue;
}
// skip boxes that shouldn't render this pass
if (boxGroup.ssaoEnabled != renderingWithSsao)
{
continue;
}
profiler.popPush("render prep");
boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired
// ignore inactive groups
if (!boxGroup.active)
{
continue;
}
// allow API users to cancel this object's rendering
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
if (cancelRendering)
{
continue;
}
// update instanced data if needed
if (this.instancedRenderingAvailable)
{
boxGroup.tryUpdateInstancedDataAsync();
// skip groups that haven't been uploaded yet
if (boxGroup.vertexBufferContainer.getState() != GlGenericObjectVertexContainer.EState.RENDER)
{
continue;
}
}
// render //
profiler.popPush("rendering");
try (IProfilerWrapper.IProfileBlock namespace_profile = profiler.push(boxGroup.getResourceLocationNamespace());
IProfilerWrapper.IProfileBlock location_profile = profiler.push(boxGroup.getResourceLocationPath()))
{
if (this.instancedRenderingAvailable)
{
this.renderBoxGroupInstanced(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
}
else
{
this.renderBoxGroupDirect(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
}
}
boxGroup.postRender(renderEventParam);
}
//==========//
// clean up //
//==========//
profiler.popPush("cleanup");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
if (renderWireframe)
{
// default back to GL_FILL since all other rendering uses it
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GLMC.enableFaceCulling();
}
shaderProgram.unbind();
} }
//==========//
// clean up //
//==========//
profiler.popPush("cleanup");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
if (renderWireframe)
{
// default back to GL_FILL since all other rendering uses it
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GLMC.enableFaceCulling();
}
shaderProgram.unbind();
profiler.pop();
} }
//endregion //endregion
@@ -556,72 +556,71 @@ public class GlGenericObjectRenderer implements IDhGenericRenderer
RenderableBoxGroup boxGroup, Vec3d camPos, RenderableBoxGroup boxGroup, Vec3d camPos,
IProfilerWrapper profiler) IProfilerWrapper profiler)
{ {
// update instance data // try (IProfilerWrapper.IProfileBlock render_profile = profiler.push("vertex setup"))
profiler.push("vertex setup");
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
if (shading == null)
{ {
shading = DEFAULT_SHADING;
}
shaderProgram.fillIndirectUniformData( // update instance data //
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
if (shading == null)
{
shading = DEFAULT_SHADING;
}
shaderProgram.fillIndirectUniformData(
renderEventParam, renderEventParam,
shading, boxGroup, shading, boxGroup,
camPos); camPos);
// Bind instance data // // Bind instance data //
profiler.popPush("binding"); profiler.popPush("binding");
GlGenericObjectVertexContainer container = (GlGenericObjectVertexContainer)(boxGroup.vertexBufferContainer); GlGenericObjectVertexContainer container = (GlGenericObjectVertexContainer) (boxGroup.vertexBufferContainer);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.color); GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.color);
GL32.glEnableVertexAttribArray(1); GL32.glEnableVertexAttribArray(1);
GL32.glVertexAttribPointer(1, 4, GL32.GL_FLOAT, false, 4 * Float.BYTES, 0); GL32.glVertexAttribPointer(1, 4, GL32.GL_FLOAT, false, 4 * Float.BYTES, 0);
this.vertexAttribDivisor(1, 1); this.vertexAttribDivisor(1, 1);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.scale); GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.scale);
GL32.glEnableVertexAttribArray(2); GL32.glEnableVertexAttribArray(2);
this.vertexAttribDivisor(2, 1); this.vertexAttribDivisor(2, 1);
GL32.glVertexAttribPointer(2, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0); GL32.glVertexAttribPointer(2, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.chunkPos); GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.chunkPos);
GL32.glEnableVertexAttribArray(3); GL32.glEnableVertexAttribArray(3);
this.vertexAttribDivisor(3, 1); this.vertexAttribDivisor(3, 1);
GL32.glVertexAttribIPointer(3, 3, GL32.GL_INT, 3 * Integer.BYTES, 0); GL32.glVertexAttribIPointer(3, 3, GL32.GL_INT, 3 * Integer.BYTES, 0);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.subChunkPos); GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.subChunkPos);
GL32.glEnableVertexAttribArray(4); GL32.glEnableVertexAttribArray(4);
this.vertexAttribDivisor(4, 1); this.vertexAttribDivisor(4, 1);
GL32.glVertexAttribPointer(4, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0); GL32.glVertexAttribPointer(4, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.material); GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.material);
GL32.glEnableVertexAttribArray(5); GL32.glEnableVertexAttribArray(5);
this.vertexAttribDivisor(5, 1); this.vertexAttribDivisor(5, 1);
GL32.glVertexAttribIPointer(5, 1, GL32.GL_BYTE, Byte.BYTES, 0); GL32.glVertexAttribIPointer(5, 1, GL32.GL_BYTE, Byte.BYTES, 0);
// Draw instanced // Draw instanced
profiler.popPush("render"); profiler.popPush("render");
if (container.uploadedBoxCount > 0) if (container.uploadedBoxCount > 0)
{ {
GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, container.uploadedBoxCount); GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, container.uploadedBoxCount);
}
// Clean up
profiler.popPush("cleanup");
GL32.glDisableVertexAttribArray(1);
GL32.glDisableVertexAttribArray(2);
GL32.glDisableVertexAttribArray(3);
GL32.glDisableVertexAttribArray(4);
GL32.glDisableVertexAttribArray(5);
} }
// Clean up
profiler.popPush("cleanup");
GL32.glDisableVertexAttribArray(1);
GL32.glDisableVertexAttribArray(2);
GL32.glDisableVertexAttribArray(3);
GL32.glDisableVertexAttribArray(4);
GL32.glDisableVertexAttribArray(5);
profiler.pop();
} }
/** /**
* Clean way to handle both {@link GL33#glVertexAttribDivisor} and {@link ARBInstancedArrays#glVertexAttribDivisorARB} * Clean way to handle both {@link GL33#glVertexAttribDivisor} and {@link ARBInstancedArrays#glVertexAttribDivisorARB}
@@ -689,8 +688,6 @@ public class GlGenericObjectRenderer implements IDhGenericRenderer
break; break;
} }
} }
profiler.pop();
} }
//endregion //endregion
@@ -21,13 +21,17 @@ package com.seibel.distanthorizons.common.render.openGl.glObject;
import com.seibel.distanthorizons.api.enums.config.EDhApiGLErrorHandlingMode; import com.seibel.distanthorizons.api.enums.config.EDhApiGLErrorHandlingMode;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod; import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.api.enums.config.EDhApiLoggerLevel;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.EPlatform; import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.objects.GLMessages.*; import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL;
@@ -46,10 +50,30 @@ import java.util.concurrent.ConcurrentHashMap;
*/ */
public class GLProxy public class GLProxy
{ {
public static final DhLogger LOGGER = new DhLoggerBuilder() private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat) public static final DhLogger LOGGER;
.build(); static
{
DhLoggerBuilder loggerBuilder = new DhLoggerBuilder();
loggerBuilder.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile);
// don't send chat messages if Iris is present since
// Iris is known to cause (harmless) GL errors
// and this can confuse users
boolean irisPresent = (IRIS_ACCESSOR != null);
if (!irisPresent)
{
loggerBuilder.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat);
}
LOGGER = loggerBuilder.build();
if (irisPresent)
{
LOGGER.info("Iris detected, Distant Horizons OpenGL error logging won't be sent in the chat due to Iris throwing known (harmless) OpenGL errors. This is a bug with Iris, not Distant Horizons.");
}
}
public static final Set<String> LOGGED_GL_MESSAGES = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>()); public static final Set<String> LOGGED_GL_MESSAGES = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
@@ -238,7 +262,7 @@ public class GLProxy
//region //region
/** this method is called on the render thread at the point of the GL Error */ /** this method is called on the render thread at the point of the GL Error */
private static void logMessage(GLMessage msg) private static void logMessage(GLMessage glMessage)
{ {
EDhApiGLErrorHandlingMode errorHandlingMode = Config.Client.Advanced.Debugging.OpenGl.glErrorHandlingMode.get(); EDhApiGLErrorHandlingMode errorHandlingMode = Config.Client.Advanced.Debugging.OpenGl.glErrorHandlingMode.get();
if (errorHandlingMode == EDhApiGLErrorHandlingMode.IGNORE) if (errorHandlingMode == EDhApiGLErrorHandlingMode.IGNORE)
@@ -249,19 +273,26 @@ public class GLProxy
boolean onlyLogOnce = Config.Client.Advanced.Debugging.OpenGl.onlyLogGlErrorsOnce.get(); boolean onlyLogOnce = Config.Client.Advanced.Debugging.OpenGl.onlyLogGlErrorsOnce.get();
String errorMessage = "GL ERROR [" + msg.id + "] from [" + msg.source + "]: [" + msg.message + "]"+(onlyLogOnce ? " this message will only be logged once" : "")+".";
if (onlyLogOnce if (onlyLogOnce
&& !LOGGED_GL_MESSAGES.add(errorMessage)) && !LOGGED_GL_MESSAGES.add(glMessage.message))
{ {
// this message has already been logged // this message has already been logged
return; return;
} }
String errorMessage = "GL ERROR [" + glMessage.id + "] from [" + glMessage.source + "]: [" + glMessage.message + "].";
if (onlyLogOnce)
{
errorMessage += " This message will only be logged once.";
errorMessage += " Note: Distant Horizons will catch and log OpenGL errors from other mods, not just DH itself; if everything is rendering correctly these errors can probably be ignored.";
}
// create an exception so we get a stacktrace of where the message was triggered from // create an exception so we get a stacktrace of where the message was triggered from
RuntimeException exception = new RuntimeException(errorMessage); RuntimeException exception = new RuntimeException(errorMessage);
if (msg.type == EGLMessageType.ERROR || msg.type == EGLMessageType.UNDEFINED_BEHAVIOR) if (glMessage.type == EGLMessageType.ERROR || glMessage.type == EGLMessageType.UNDEFINED_BEHAVIOR)
{ {
// critical error // critical error
@@ -278,7 +309,7 @@ public class GLProxy
{ {
// non-critical log // non-critical log
EGLMessageSeverity severity = msg.severity; EGLMessageSeverity severity = glMessage.severity;
if (severity == null) if (severity == null)
{ {
// just in case the message was malformed // just in case the message was malformed
@@ -210,9 +210,12 @@ public class GLBuffer implements AutoCloseable
// re-binding the old VBO is necessary for old MC versions (IE 1.16.5 and older) // re-binding the old buffers is necessary for old MC versions for the following reasons:
// otherwise the screen may be black when on the home menu // for 16.5 and older the screen may be black when on the home menu
int previousBoundVbo = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING); // and for 1.19.2 - 1.21.4 the inventory/UI will render without a background
int vao = GL32.glGetInteger(GL32.GL_VERTEX_ARRAY_BINDING);
int vbo = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING);
int ebo = GL32.glGetInteger(GL32.GL_ELEMENT_ARRAY_BUFFER_BINDING);
try try
{ {
@@ -238,7 +241,9 @@ public class GLBuffer implements AutoCloseable
} }
finally finally
{ {
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, GL32.glIsBuffer(previousBoundVbo) ? previousBoundVbo : 0); GL32.glBindVertexArray(GL32.glIsVertexArray(vao) ? vao : 0);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, GL32.glIsBuffer(vbo) ? vbo : 0);
GL32.glBindBuffer(GL32.GL_ELEMENT_ARRAY_BUFFER, GL32.glIsBuffer(ebo) ? ebo: 0);
} }
} }
/** Requires the buffer to be bound */ /** Requires the buffer to be bound */
@@ -22,15 +22,16 @@ package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy; import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.IndexBufferBuilder;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder; import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler; import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition; import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import org.lwjgl.opengl.GL32; import org.lwjgl.opengl.GL32;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod; import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import org.lwjgl.system.MemoryUtil;
/** /**
* This is a container for a OpenGL * This is a container for a OpenGL
@@ -83,7 +84,10 @@ public class GLVertexBuffer extends GLBuffer implements IVertexBufferWrapper
int maxSize = LodQuadBuilder.getMaxBufferByteSize(); int maxSize = LodQuadBuilder.getMaxBufferByteSize();
int maxVertexCount = maxSize / LodQuadBuilder.BYTES_PER_VERTEX; int maxVertexCount = maxSize / LodQuadBuilder.BYTES_PER_VERTEX;
int maxQuadCount = (maxVertexCount / 4); int maxQuadCount = (maxVertexCount / 4);
GLOBAL_QUAD_IBO.upload(maxQuadCount);
ByteBuffer buffer = IndexBufferBuilder.createBuffer(maxQuadCount);
GLOBAL_QUAD_IBO.upload(buffer, maxQuadCount);
MemoryUtil.memFree(buffer);
}); });
} }
} }
@@ -158,7 +162,7 @@ public class GLVertexBuffer extends GLBuffer implements IVertexBufferWrapper
this.quadIBO = new GlQuadIndexBuffer(); this.quadIBO = new GlQuadIndexBuffer();
int quadCount = (vertexCount / 4); int quadCount = (vertexCount / 4);
this.quadIBO.upload(quadCount); this.quadIBO.upload(buffer, quadCount);
} }
//endregion //endregion
@@ -43,7 +43,7 @@ public class GlQuadIndexBuffer extends GLIndexBuffer
public GlQuadIndexBuffer() { super(false); } public GlQuadIndexBuffer() { super(false); }
public void upload(int quadCount) public void upload(ByteBuffer buffer, int quadCount)
{ {
if (quadCount < 0) if (quadCount < 0)
{ {
@@ -63,12 +63,8 @@ public class GlQuadIndexBuffer extends GLIndexBuffer
} }
this.glType = GL32.GL_UNSIGNED_INT; this.glType = GL32.GL_UNSIGNED_INT;
ByteBuffer buffer = IndexBufferBuilder.createBuffer(quadCount);
this.bind();
super.uploadBuffer(buffer, EDhApiGpuUploadMethod.DATA, super.uploadBuffer(buffer, EDhApiGpuUploadMethod.DATA,
this.indicesCount * GLEnums.getTypeSize(this.glType), GL32.GL_STATIC_DRAW); this.indicesCount * GLEnums.getTypeSize(this.glType), GL32.GL_STATIC_DRAW);
MemoryUtil.memFree(buffer);
} }
//endregion //endregion
@@ -122,8 +122,6 @@ public class GlDhFarFadeRenderer implements IDhFarFadeRenderer
{ {
try try
{ {
//profiler.push("Fade Generate");
this.init(); this.init();
// resize the framebuffer if necessary // resize the framebuffer if necessary
@@ -141,8 +139,6 @@ public class GlDhFarFadeRenderer implements IDhFarFadeRenderer
GlDhFarFadeShader.INSTANCE.setProjectionMatrix(renderParams.mcModelViewMatrix, renderParams.mcProjectionMatrix); GlDhFarFadeShader.INSTANCE.setProjectionMatrix(renderParams.mcModelViewMatrix, renderParams.mcProjectionMatrix);
GlDhFarFadeShader.INSTANCE.render(renderParams); GlDhFarFadeShader.INSTANCE.render(renderParams);
//profiler.popPush("Fade Apply");
GlDhFarFadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture; GlDhFarFadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture;
GlDhFarFadeApplyShader.INSTANCE.readFramebuffer = GlDhFarFadeShader.INSTANCE.frameBuffer; GlDhFarFadeApplyShader.INSTANCE.readFramebuffer = GlDhFarFadeShader.INSTANCE.frameBuffer;
GlDhFarFadeApplyShader.INSTANCE.drawFramebuffer = GlDhMetaRenderer.INSTANCE.getActiveFramebufferId(); GlDhFarFadeApplyShader.INSTANCE.drawFramebuffer = GlDhMetaRenderer.INSTANCE.getActiveFramebufferId();
@@ -152,10 +148,6 @@ public class GlDhFarFadeRenderer implements IDhFarFadeRenderer
{ {
LOGGER.error("Unexpected error during fade render, error: ["+e.getMessage()+"].", e); LOGGER.error("Unexpected error during fade render, error: ["+e.getMessage()+"].", e);
} }
finally
{
//profiler.pop();
}
} }
//emdregion //emdregion
@@ -135,14 +135,9 @@ public class GlVanillaFadeRenderer implements IDhVanillaFadeRenderer
IProfilerWrapper profiler = MC_CLIENT.getProfiler(); IProfilerWrapper profiler = MC_CLIENT.getProfiler();
profiler.pop(); // get out of "terrain" try (IProfilerWrapper.IProfileBlock fade_profile = profiler.push("DH-Vanilla Fade");
profiler.push("DH-Vanilla Fade"); GLState mcState = new GLState())
try(GLState mcState = new GLState())
{ {
profiler.push("Vanilla Fade Generate");
this.init(); this.init();
// resize the framebuffer if necessary // resize the framebuffer if necessary
@@ -165,19 +160,15 @@ public class GlVanillaFadeRenderer implements IDhVanillaFadeRenderer
// otherwise we can directly render to their texture // otherwise we can directly render to their texture
if (MC_RENDER.mcRendersToFrameBuffer()) if (MC_RENDER.mcRendersToFrameBuffer())
{ {
profiler.popPush("Vanilla Fade Apply");
GlDhFarFadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture; GlDhFarFadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture;
GlDhFarFadeApplyShader.INSTANCE.readFramebuffer = GlDhVanillaFadeShader.INSTANCE.frameBuffer; GlDhFarFadeApplyShader.INSTANCE.readFramebuffer = GlDhVanillaFadeShader.INSTANCE.frameBuffer;
GlDhFarFadeApplyShader.INSTANCE.drawFramebuffer = MC_RENDER.getTargetFramebuffer(); GlDhFarFadeApplyShader.INSTANCE.drawFramebuffer = MC_RENDER.getTargetFramebuffer();
GlDhFarFadeApplyShader.INSTANCE.render(renderParams); GlDhFarFadeApplyShader.INSTANCE.render(renderParams);
} }
profiler.pop();
} }
catch (Exception e) catch (Exception e)
{ {
LOGGER.error("Unexpected error during fade render, error: ["+e.getMessage()+"].", e); LOGGER.error("Unexpected error during fade render, error: [" + e.getMessage() + "].", e);
} }
} }
@@ -296,8 +296,6 @@ public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiS
// rendering // // rendering //
//===========// //===========//
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam);
if (IRIS_ACCESSOR != null) if (IRIS_ACCESSOR != null)
{ {
// done to fix a bug with Iris where face culling isn't properly set or reverted in the MC state manager // done to fix a bug with Iris where face culling isn't properly set or reverted in the MC state manager
@@ -25,7 +25,7 @@ import com.seibel.distanthorizons.common.render.blaze.BlazeDhRenderApiDefinition
import com.seibel.distanthorizons.common.render.openGl.GlDhRenderApiDefinition; import com.seibel.distanthorizons.common.render.openGl.GlDhRenderApiDefinition;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory; import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
import com.seibel.distanthorizons.common.wrappers.gui.ClassicConfigGUI; import com.seibel.distanthorizons.common.wrappers.gui.classicConfig.ClassicConfigGUI;
import com.seibel.distanthorizons.common.wrappers.gui.LangWrapper; import com.seibel.distanthorizons.common.wrappers.gui.LangWrapper;
import com.seibel.distanthorizons.common.wrappers.level.KeyedClientLevelManager; import com.seibel.distanthorizons.common.wrappers.level.KeyedClientLevelManager;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
@@ -93,8 +93,8 @@ public class VersionConstants implements IVersionConstants
return "1.21.10"; return "1.21.10";
#elif MC_VER == MC_1_21_11 #elif MC_VER == MC_1_21_11
return "1.21.11"; return "1.21.11";
#elif MC_VER == MC_1_26_1 #elif MC_VER == MC_26_1_2
return "21.6"; return "26.1.2";
#else #else
ERROR MC version constant missing ERROR MC version constant missing
#endif #endif
@@ -104,10 +104,10 @@ public class VersionConstants implements IVersionConstants
@Override @Override
public EDhApiRenderApi getDefaultRenderingApi() public EDhApiRenderApi getDefaultRenderingApi()
{ {
#if MC_VER <= MC_1_26_1 #if MC_VER <= MC_1_21_11
return EDhApiRenderApi.OPEN_GL; return EDhApiRenderApi.OPEN_GL;
#else #else
ERROR MC version constant missing return EDhApiRenderApi.BLAZE_3D;
#endif #endif
} }
@@ -6,7 +6,7 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSour
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable;
import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import com.seibel.distanthorizons.core.util.FullDataPointUtil; import com.seibel.distanthorizons.core.util.FullDataPointUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
@@ -46,7 +46,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
private static final ConcurrentHashMap<BlockBiomeWrapperPair, Integer> COLOR_BY_BLOCK_BIOME_PAIR = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<BlockBiomeWrapperPair, Integer> COLOR_BY_BLOCK_BIOME_PAIR = new ConcurrentHashMap<>();
/** returned if the color cache is incomplete */ /** returned if the color cache is incomplete */
public static final int INVALID_COLOR = Integer.MIN_VALUE; public static final int INVALID_COLOR = -1;
protected BiomeWrapper biomeWrapper; protected BiomeWrapper biomeWrapper;
@@ -60,6 +60,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
//=============// //=============//
// constructor // // constructor //
//=============// //=============//
//region
public AbstractDhTintGetter() { } public AbstractDhTintGetter() { }
@@ -76,11 +77,14 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
this.smoothingRadiusInBlocks = Config.Client.Advanced.Graphics.Quality.lodBiomeBlending.get(); this.smoothingRadiusInBlocks = Config.Client.Advanced.Graphics.Quality.lodBiomeBlending.get();
} }
//endregion
//================//
// shared methods // //===============//
//================// // color getters //
//===============//
//region
/** Called by MC's tint getter */ /** Called by MC's tint getter */
@Override @Override
@@ -195,7 +199,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
BlockBiomeWrapperPair pair = BlockBiomeWrapperPair.get(this.blockStateWrapper, biomeWrapper); BlockBiomeWrapperPair pair = BlockBiomeWrapperPair.get(this.blockStateWrapper, biomeWrapper);
// use the cached color if possible // use the cached color if possible
Integer cachedColor = COLOR_BY_BLOCK_BIOME_PAIR.get(pair); // explicit Integer return here reduces unnecessary allocations Integer cachedColor = COLOR_BY_BLOCK_BIOME_PAIR.get(pair);
if (cachedColor != null) if (cachedColor != null)
{ {
return cachedColor; return cachedColor;
@@ -335,6 +339,27 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
}); });
} }
//endregion
//===========//
// set color //
//===========//
//region
/**
* can be used in newer MC versions
* where the color getting logic is a bit more manual
*/
public static void setStaticColor(BlockStateWrapper blockStateWrapper, BiomeWrapper biomeWrapper, Integer colorInt)
{
BlockBiomeWrapperPair pair = BlockBiomeWrapperPair.get(blockStateWrapper, biomeWrapper);
COLOR_BY_BLOCK_BIOME_PAIR.put(pair, colorInt);
}
//endregion
} }
@@ -232,12 +232,13 @@ public class BiomeWrapper implements IBiomeWrapper
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome); resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome);
#elif MC_VER <= MC_1_19_2 #elif MC_VER <= MC_1_19_2
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value()); resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value());
#elif MC_VER <= MC_1_21_4 #elif MC_VER <= MC_1_21_1
resourceLocation = registryAccess.registryOrThrow(Registries.BIOME).getKey(this.biome.value()); resourceLocation = registryAccess.registryOrThrow(Registries.BIOME).getKey(this.biome.value());
#else #else
resourceLocation = registryAccess.lookupOrThrow(Registries.BIOME).getKey(this.biome.value()); resourceLocation = registryAccess.lookupOrThrow(Registries.BIOME).getKey(this.biome.value());
#endif #endif
if (resourceLocation == null) if (resourceLocation == null)
{ {
String biomeName; String biomeName;
@@ -362,7 +363,7 @@ public class BiomeWrapper implements IBiomeWrapper
Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation); Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
success = (unwrappedBiome != null); success = (unwrappedBiome != null);
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome); Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
#elif MC_VER <= MC_1_21_4 #elif MC_VER <= MC_1_21_1
Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation); Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
success = (unwrappedBiome != null); success = (unwrappedBiome != null);
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome); Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
@@ -19,22 +19,21 @@
package com.seibel.distanthorizons.common.wrappers.block; package com.seibel.distanthorizons.common.wrappers.block;
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper;
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBlockColorOverrideEvent;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter; import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable;
import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.*;
#if MC_VER >= MC_1_19_2
import net.minecraft.util.RandomSource;
#else
import java.util.Random;
#endif
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.block.state.properties.SlabType;
@@ -45,6 +44,12 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
#if MC_VER >= MC_1_19_2
import net.minecraft.util.RandomSource;
#else
import java.util.Random;
#endif
#if MC_VER < MC_1_21_5 #if MC_VER < MC_1_21_5
import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BakedQuad;
#elif MC_VER <= MC_1_21_11 #elif MC_VER <= MC_1_21_11
@@ -53,6 +58,8 @@ import net.minecraft.client.renderer.block.model.BakedQuad;
#else #else
import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart;
import net.minecraft.client.resources.model.geometry.BakedQuad; import net.minecraft.client.resources.model.geometry.BakedQuad;
import net.minecraft.core.BlockPos;
import net.minecraft.client.color.block.BlockTintSource;
#endif #endif
/** /**
@@ -119,6 +126,7 @@ public class ClientBlockStateColorCache
//===========// //===========//
// constants // // constants //
//===========// //===========//
//region
private static final int MIN_SRGB_BITS = 0x39000000; // 2^(-13) private static final int MIN_SRGB_BITS = 0x39000000; // 2^(-13)
private static final int MAX_SRGB_BITS = 0x3f7fffff; // 1.0 - f32::EPSILON private static final int MAX_SRGB_BITS = 0x3f7fffff; // 1.0 - f32::EPSILON
@@ -182,14 +190,19 @@ public class ClientBlockStateColorCache
//endregion //endregion
}; };
private static final ThreadLocal<TintWithoutLevelOverrider> TintWithoutLevelOverrideGetter = ThreadLocal.withInitial(() -> new TintWithoutLevelOverrider()); // these are threadlocals since AbstractDhTintGetter use local variables to handle color queries
private static final ThreadLocal<TintGetterOverride> TintOverrideGetter = ThreadLocal.withInitial(() -> new TintGetterOverride()); private static final ThreadLocal<TintWithoutLevelOverrider> TintWithoutLevelOverrideGetter = ThreadLocal.withInitial(TintWithoutLevelOverrider::new);
private static final ThreadLocal<TintGetterOverride> TintOverrideGetter = ThreadLocal.withInitial(TintGetterOverride::new);
private static final ThreadLocal<DhApiBlockColorOverrideEvent.EventParam> ColorOverrideEventParamGetter = ThreadLocal.withInitial(DhApiBlockColorOverrideEvent.EventParam::new);
//endregion
//=============// //=============//
// constructor // // constructor //
//=============// //=============//
//region
public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper clientLevelWrapper) public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper clientLevelWrapper)
{ {
@@ -200,6 +213,8 @@ public class ClientBlockStateColorCache
this.resolveColors(); this.resolveColors();
} }
//endregion
//===================// //===================//
@@ -504,60 +519,89 @@ public class ClientBlockStateColorCache
public int getColor(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, DhBlockPos blockPos) public int getColor(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, DhBlockPos blockPos)
{ {
// only get the tint if the block needs to be tinted // only get the tint if the block needs to be tinted
if (!this.needPostTinting) int tintColor = AbstractDhTintGetter.INVALID_COLOR;
if (this.needPostTinting)
{ {
return this.baseColor; // don't try tinting blocks that don't support our method of tint getting
} if (BROKEN_BLOCK_STATES.contains(this.blockState))
// don't try tinting blocks that don't support our method of tint getting
if (BROKEN_BLOCK_STATES.contains(this.blockState))
{
return this.baseColor;
}
// attempt to get the tint
int tintColor = -1;
try
{
// try to use the fast tint getter logic first
if (!BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
{ {
try return this.baseColor;
{ }
TintWithoutLevelOverrider tintOverride = TintWithoutLevelOverrideGetter.get();
tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper);
// try using DH's cached tint values first if possible
tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos)); // attempt to get the tint
if (tintColor == AbstractDhTintGetter.INVALID_COLOR) try
{
// try to use the fast tint getter logic first
if (!BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
{
try
{ {
// one or more tint values weren't calculated, TintWithoutLevelOverrider tintOverride = TintWithoutLevelOverrideGetter.get();
// we need MC's color resolver tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper);
// try using DH's cached tint values first if possible
tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos));
if (tintColor == AbstractDhTintGetter.INVALID_COLOR)
{
// one or more tint values weren't calculated,
// we need MC's color resolver
#if MC_VER <= MC_1_21_11 #if MC_VER <= MC_1_21_11
tintColor = Minecraft.getInstance() tintColor = Minecraft.getInstance()
.getBlockColors() .getBlockColors()
.getColor(this.blockState, .getColor(this.blockState,
tintOverride, tintOverride, // tintOverride will save the result of this query to speed up future queries
McObjectConverter.Convert(blockPos), McObjectConverter.Convert(blockPos),
this.tintIndex); this.tintIndex);
#else #else
tintColor = Minecraft.getInstance() BlockTintSource tintSource = Minecraft.getInstance()
.getBlockColors() .getBlockColors()
.getTintSources(this.blockState) .getTintSource(this.blockState, this.tintIndex);
.get(this.tintIndex) // a tint source may be null for blocks that don't actually need tinting
.color(this.blockState); // in that case the base color should be sufficient
// Example: cherry blossom leaves
if (tintSource != null)
{
BlockPos mcPos = McObjectConverter.Convert(blockPos);
tintColor = tintSource.colorInWorld(this.blockState, tintOverride, mcPos);
if (tintColor == -1)
{
tintColor = tintSource.colorAsTerrainParticle(this.blockState, tintOverride, mcPos);
}
}
if (tintColor == -1)
{
// no color found, use the base color
tintColor = AbstractDhTintGetter.INVALID_COLOR;
}
// save this color to speed up future queries
TintWithoutLevelOverrider.setStaticColor(this.blockStateWrapper, biomeWrapper, tintColor);
// try to get the blended color with this new information
tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos));
#endif #endif
}
} }
} catch (Exception e)
catch (UnsupportedOperationException e) {
{ #if MC_VER <= MC_1_21_11
// this exception generally occurs if the tint requires other blocks besides itself // this exception generally occurs if the tint requires other blocks besides itself
LOGGER.debug("Unable to use ["+ TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e); LOGGER.debug("Unable to use ["+ TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e);
BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState); BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState);
#else
// only display the error once per block/biome type to reduce log spam
if (!BROKEN_BLOCK_STATES.contains(this.blockState))
{
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: [" + e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
BROKEN_BLOCK_STATES.add(this.blockState);
}
#endif
}
} }
}
// level-specific logic is only needed for MC 1.21.11 and older
#if MC_VER <= MC_1_21_11
// use the level logic only if requested // use the level logic only if requested
if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState)) if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
{ {
@@ -570,44 +614,57 @@ public class ClientBlockStateColorCache
tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos)); tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos));
if (tintColor == AbstractDhTintGetter.INVALID_COLOR) if (tintColor == AbstractDhTintGetter.INVALID_COLOR)
{ {
#if MC_VER <= MC_1_21_11
tintColor = Minecraft.getInstance() tintColor = Minecraft.getInstance()
.getBlockColors() .getBlockColors()
.getColor(this.blockState, .getColor(this.blockState,
tintOverride, tintOverride,
McObjectConverter.Convert(blockPos), McObjectConverter.Convert(blockPos),
this.tintIndex); this.tintIndex);
#else }
tintColor = Minecraft.getInstance() }
.getBlockColors() #endif
.getTintSources(this.blockState) }
.get(this.tintIndex) catch (Exception e)
.color(this.blockState); {
#endif // only display the error once per block/biome type to reduce log spam
if (!BROKEN_BLOCK_STATES.contains(this.blockState))
{
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: [" + e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
BROKEN_BLOCK_STATES.add(this.blockState);
} }
} }
} }
catch (Exception e)
int returnColor;
if (tintColor != AbstractDhTintGetter.INVALID_COLOR)
{ {
// only display the error once per block/biome type to reduce log spam returnColor = ColorUtil.multiplyARGBwithRGB(this.baseColor, tintColor);
if (!BROKEN_BLOCK_STATES.contains(this.blockState))
{
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
BROKEN_BLOCK_STATES.add(this.blockState);
}
}
if (tintColor != -1)
{
return ColorUtil.multiplyARGBwithRGB(this.baseColor, tintColor);
} }
else else
{ {
// unable to get the tinted color, use the base color instead // unable to get the tinted color, use the base color instead
return this.baseColor; returnColor = this.baseColor;
} }
// only fire an API event if needed
// (this is done to reduce GC pressure and speed up color getting)
if (this.blockStateWrapper.allowApiColorOverride())
{
DhApiBlockColorOverrideEvent.EventParam eventParam = ColorOverrideEventParamGetter.get();
eventParam.update(
this.clientLevelWrapper,
this.blockStateWrapper, returnColor,
blockPos.getX(), blockPos.getY(), blockPos.getZ()
);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBlockColorOverrideEvent.class, eventParam);
// let the API user override this color
returnColor = eventParam.getColorAsInt();
}
return returnColor;
} }
@@ -615,6 +672,7 @@ public class ClientBlockStateColorCache
//================// //================//
// helper classes // // helper classes //
//================// //================//
//region
private enum EColorMode private enum EColorMode
{ {
@@ -646,6 +704,8 @@ public class ClientBlockStateColorCache
} }
} }
//endregion
} }
@@ -25,7 +25,7 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite;
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
#elif MC_VER < MC_1_21_3 #elif MC_VER < MC_1_21_3
#else #else
import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import net.minecraft.client.renderer.texture.SpriteContents; import net.minecraft.client.renderer.texture.SpriteContents;
#endif #endif
@@ -1,5 +1,6 @@
package com.seibel.distanthorizons.common.wrappers.gui; package com.seibel.distanthorizons.common.wrappers.gui;
import com.seibel.distanthorizons.common.wrappers.gui.classicConfig.ClassicConfigGUI;
import com.seibel.distanthorizons.core.config.ConfigHandler; import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
@@ -0,0 +1,38 @@
package com.seibel.distanthorizons.common.wrappers.gui;
import org.lwjgl.util.tinyfd.TinyFileDialogs;
/**
* Should be used instead of the direct call to {@link TinyFileDialogs}
* so we can run additional validation and/or string cleanup.
* Otherwise, we may get error messages back. <br><br>
*
* source:
* https://sourceforge.net/projects/tinyfiledialogs/
*
* @see TinyFileDialogs
*/
public class NativeDialogUtil
{
/**
* @param dialogType the dialog type. One of:<br><table><tr><td>"ok"</td><td>"okcancel"</td><td>"yesno"</td><td>"yesnocancel"</td></tr></table>
* @param iconType the icon type. One of:<br><table><tr><td>"info"</td><td>"warning"</td><td>"error"</td><td>"question"</td></tr></table>
*/
public static void showDialog(String title, String message, String dialogType, String iconType)
{
// Tinyfd doesn't support the following characters, attempting to display them will cause the message
// to be replaced with an error message
String unsafeCharsRegex = "['\"`]";
title = title.replaceAll(unsafeCharsRegex, "");
message = message.replaceAll(unsafeCharsRegex, "");
#if MC_VER <= MC_1_21_11
TinyFileDialogs.tinyfd_messageBox(title, message, dialogType, iconType, false);
#else
// https://mfbridge.github.io/tinyfiledialogs/reference/messageBox.html
TinyFileDialogs.tinyfd_messageBox(title, message, dialogType, iconType, 1 /* ok/yes */);
#endif
}
}
@@ -218,11 +218,11 @@ public class TexturedButtonWidget extends Button
this.getX(), this.getY(), this.getX(), this.getY(),
this.getWidth(), this.getHeight()); this.getWidth(), this.getHeight());
#else #else
//matrices.blitSprite( matrices.blitSprite(
// RenderPipelines.GUI_TEXTURED, RenderPipelines.GUI_TEXTURED,
// SPRITES.get(this.active, this.isHoveredOrFocused()), SPRITES.get(this.active, this.isHoveredOrFocused()),
// this.getX(), this.getY(), this.getX(), this.getY(),
// this.getWidth(), this.getHeight()); this.getWidth(), this.getHeight());
#endif #endif
} }
@@ -0,0 +1,384 @@
package com.seibel.distanthorizons.common.wrappers.gui.classicConfig;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import com.seibel.distanthorizons.core.config.types.*;
import com.seibel.distanthorizons.core.config.types.enums.EConfigCommentTextPosition;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.NotNull;
#if MC_VER < MC_1_20_1
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.GuiComponent;
#elif MC_VER <= MC_1_21_11
import net.minecraft.client.gui.GuiGraphics;
#else
import net.minecraft.client.gui.GuiGraphicsExtractor;
#endif
#if MC_VER >= MC_1_17_1
import net.minecraft.client.gui.narration.NarratableEntry;
#endif
#if MC_VER <= MC_1_21_10
#else
import net.minecraft.resources.Identifier;
#endif
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
/*
* Based upon TinyConfig but is highly modified
* https://github.com/Minenash/TinyConfig
*
* @author coolGi
* @author Motschen
* @author James Seibel
* @version 5-21-2022
*/
@SuppressWarnings("unchecked")
public class ClassicConfigGUI
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
public static final DhLogger RATE_LIMITED_LOGGER = new DhLoggerBuilder()
.maxCountPerSecond(1)
.build();
public static final ConfigCoreInterface CONFIG_CORE_INTERFACE = new ConfigCoreInterface();
//==============//
// Initializers //
//==============//
// Some regexes to check if an input is valid
public static final Pattern INTEGER_ONLY_REGEX = Pattern.compile("(-?[0-9]*)");
public static final Pattern DECIMAL_ONLY_REGEX = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
public static class ConfigScreenConfigs
{
// This contains all the configs for the configs
public static final int SPACE_FROM_RIGHT_SCREEN = 10;
public static final int SPACE_BETWEEN_TEXT_AND_OPTION_FIELD = 8;
public static final int BUTTON_WIDTH_SPACING = 5;
public static final int RESET_BUTTON_WIDTH = 60;
public static final int RESET_BUTTON_HEIGHT = 20;
public static final int OPTION_FIELD_WIDTH = 150;
public static final int OPTION_FIELD_HEIGHT = 20;
public static final int CATEGORY_BUTTON_WIDTH = 200;
public static final int CATEGORY_BUTTON_HEIGHT = 20;
}
//==============//
// GUI handling //
//==============//
/** if you want to get this config gui's screen call this */
public static Screen getScreen(Screen parent, String category)
{ return new DhConfigScreen(parent, category); }
//================//
// helper classes //
//================//
public static class ConfigListWidget extends ContainerObjectSelectionList<DhButtonEntry>
{
Font textRenderer;
public ConfigListWidget(Minecraft minecraftClient, int canvasWidth, int canvasHeight, int topMargin, int botMargin, int itemSpacing)
{
#if MC_VER < MC_1_20_4
super(minecraftClient, canvasWidth, canvasHeight, topMargin, canvasHeight - botMargin, itemSpacing);
#else
super(minecraftClient, canvasWidth, canvasHeight - (topMargin + botMargin), topMargin, itemSpacing);
#endif
this.centerListVertically = false;
this.textRenderer = minecraftClient.font;
}
public void addButton(DhConfigScreen gui, AbstractConfigBase dhConfigType, AbstractWidget button, AbstractWidget resetButton, AbstractWidget indexButton, Component text)
{ this.addEntry(new DhButtonEntry(gui, dhConfigType, button, text, resetButton, indexButton)); }
@Override
public int getRowWidth() { return 10_000; }
public AbstractWidget getHoveredButton(double mouseX, double mouseY)
{
for (DhButtonEntry buttonEntry : this.children())
{
AbstractWidget button = buttonEntry.button;
if (button != null
&& button.visible)
{
#if MC_VER < MC_1_19_4
double minX = button.x;
double minY = button.y;
#else
double minX = button.getX();
double minY = button.getY();
#endif
double maxX = minX + button.getWidth();
double maxY = minY + button.getHeight();
if (mouseX >= minX && mouseX < maxX
&& mouseY >= minY && mouseY < maxY)
{
return button;
}
}
}
return null;
}
}
public static class DhButtonEntry extends ContainerObjectSelectionList.Entry<DhButtonEntry>
{
private static final Font textRenderer = Minecraft.getInstance().font;
private final AbstractWidget button;
private final DhConfigScreen gui;
private final AbstractWidget resetButton;
private final AbstractWidget indexButton;
private final Component text;
private final List<AbstractWidget> children = new ArrayList<>();
@NotNull
private final EConfigCommentTextPosition textPosition;
public final AbstractConfigBase dhConfigType;
public static final Map<AbstractWidget, Component> TEXT_BY_WIDGET = new HashMap<>();
public static final Map<AbstractWidget, DhButtonEntry> BUTTON_BY_WIDGET = new HashMap<>();
public DhButtonEntry(
DhConfigScreen gui, AbstractConfigBase dhConfigType,
AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton)
{
TEXT_BY_WIDGET.put(button, text);
BUTTON_BY_WIDGET.put(button, this);
this.gui = gui;
this.dhConfigType = dhConfigType;
this.button = button;
this.resetButton = resetButton;
this.text = text;
this.indexButton = indexButton;
if (button != null) { this.children.add(button); }
if (resetButton != null) { this.children.add(resetButton); }
if (indexButton != null) { this.children.add(indexButton); }
EConfigCommentTextPosition textPosition = null;
if (this.dhConfigType instanceof ConfigUIComment)
{
textPosition = ((ConfigUIComment)this.dhConfigType).textPosition;
}
if (textPosition == null)
{
if (this.button != null)
{
// if a button is present
textPosition = EConfigCommentTextPosition.RIGHT_JUSTIFIED;
}
else
{
textPosition = EConfigCommentTextPosition.CENTERED_OVER_BUTTONS;
}
}
this.textPosition = textPosition;
}
@Override
#if MC_VER < MC_1_20_1
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
#elif MC_VER < MC_1_21_9
public void render(GuiGraphics matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
#elif MC_VER <= MC_1_21_11
public void renderContent(GuiGraphics matrices, int mouseX, int mouseY, boolean hovered, float tickDelta)
#else
public void extractContent(GuiGraphicsExtractor matrices, int mouseX, int mouseY, boolean hovered, float tickDelta)
#endif
{
try
{
// setting the "y" variable is necessary so each child item
// renders at the correct height,
// if not set they will render off-screen.
#if MC_VER < MC_1_21_9
// Y value passed in from method args
#else
int y = this.getY();
#endif
if (this.button != null)
{
SetY(this.button, y);
#if MC_VER <= MC_1_21_11
this.button.render(matrices, mouseX, mouseY, tickDelta);
#else
this.button.extractRenderState(matrices, mouseX, mouseY, tickDelta);
#endif
}
if (this.resetButton != null)
{
SetY(this.resetButton, y);
#if MC_VER <= MC_1_21_11
this.resetButton.render(matrices, mouseX, mouseY, tickDelta);
#else
this.resetButton.extractRenderState(matrices, mouseX, mouseY, tickDelta);
#endif
}
if (this.indexButton != null)
{
SetY(this.indexButton, y);
#if MC_VER <= MC_1_21_11
this.indexButton.render(matrices, mouseX, mouseY, tickDelta);
#else
this.indexButton.extractRenderState(matrices, mouseX, mouseY, tickDelta);
#endif
}
if (this.text != null)
{
int translatedLength = textRenderer.width(this.text);
int textXPos;
if (this.textPosition == EConfigCommentTextPosition.RIGHT_JUSTIFIED)
{
// text right justified aligned against the buttons
textXPos = this.gui.width
- translatedLength
- ConfigScreenConfigs.SPACE_BETWEEN_TEXT_AND_OPTION_FIELD
- ConfigScreenConfigs.SPACE_FROM_RIGHT_SCREEN
- ConfigScreenConfigs.OPTION_FIELD_WIDTH
- ConfigScreenConfigs.BUTTON_WIDTH_SPACING
- ConfigScreenConfigs.RESET_BUTTON_WIDTH;
}
else if (this.textPosition == EConfigCommentTextPosition.CENTERED_OVER_BUTTONS)
{
// have button centered relative to a category button
textXPos = this.gui.width
- (translatedLength / 2)
- (ConfigScreenConfigs.CATEGORY_BUTTON_WIDTH / 2)
- ConfigScreenConfigs.SPACE_FROM_RIGHT_SCREEN;
}
else if (this.textPosition == EConfigCommentTextPosition.CENTER_OF_SCREEN)
{
// have button centered in the screen
textXPos = (this.gui.width / 2)
- (translatedLength / 2);
}
else
{
throw new UnsupportedOperationException("No text position render defined for [" + this.textPosition + "]");
}
#if MC_VER < MC_1_20_1
GuiComponent.drawString(matrices, textRenderer,
this.text,
textXPos, y + 5,
0xFFFFFF);
#elif MC_VER < MC_1_21_6
matrices.drawString(textRenderer,
this.text,
textXPos, y + 5,
0xFFFFFF);
#elif MC_VER <= MC_1_21_11
matrices.drawString(textRenderer,
this.text,
textXPos, y + 5,
0xFFFFFFFF);
#else
matrices.text(textRenderer,
this.text,
textXPos, y + 5,
0xFFFFFFFF);
#endif
}
}
catch (Exception e)
{
// should prevent crashing the game if there's an issue
RATE_LIMITED_LOGGER.error("Unexpected gui rendering issue: ["+e.getMessage()+"]", e);
}
}
@Override
public @NotNull List<? extends GuiEventListener> children()
{ return this.children; }
#if MC_VER >= MC_1_17_1
@Override
public @NotNull List<? extends NarratableEntry> narratables()
{ return this.children; }
#endif
}
//================//
// event handling //
//================//
public static class ConfigCoreInterface implements IConfigGui
{
/**
* in the future it would be good to pass in the current page and other variables,
* but for now just knowing when the page is closed is good enough
*/
public final ArrayList<Runnable> onScreenChangeListenerList = new ArrayList<>();
@Override
public void addOnScreenChangeListener(Runnable newListener) { this.onScreenChangeListenerList.add(newListener); }
@Override
public void removeOnScreenChangeListener(Runnable oldListener) { this.onScreenChangeListenerList.remove(oldListener); }
}
}
@@ -0,0 +1,799 @@
package com.seibel.distanthorizons.common.wrappers.gui.classicConfig;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui;
import com.seibel.distanthorizons.common.wrappers.gui.DhScreen;
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
import com.seibel.distanthorizons.common.wrappers.gui.config.ConfigGuiInfo;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.types.*;
import com.seibel.distanthorizons.common.wrappers.gui.updater.ChangelogScreen;
import com.seibel.distanthorizons.core.config.types.enums.EConfigCommentTextPosition;
import com.seibel.distanthorizons.core.config.types.enums.EConfigValidity;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.AnnotationUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
#if MC_VER < MC_1_20_1
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.GuiComponent;
#elif MC_VER <= MC_1_21_11
import net.minecraft.client.gui.GuiGraphics;
#else
import net.minecraft.client.gui.GuiGraphicsExtractor;
#endif
#if MC_VER >= MC_1_17_1
import net.minecraft.client.gui.narration.NarratableEntry;
#endif
#if MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
#endif
import org.lwjgl.glfw.GLFW;
import com.mojang.blaze3d.platform.InputConstants;
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.Translatable;
class DhConfigScreen extends DhScreen
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final ILangWrapper LANG_WRAPPER = SingletonInjector.INSTANCE.get(ILangWrapper.class);
private static final String TRANSLATION_PREFIX = ModInfo.ID + ".config.";
private static final MinecraftClientWrapper MC_CLIENT = MinecraftClientWrapper.INSTANCE;
private final Screen parent;
private final String category;
private ClassicConfigGUI.ConfigListWidget configListWidget;
private boolean reload = false;
private Button doneButton;
//=============//
// constructor //
//=============//
protected DhConfigScreen(Screen parent, String category)
{
super(Translatable(
LANG_WRAPPER.langExists(ModInfo.ID + ".config" + (category.isEmpty() ? "." + category : "") + ".title") ?
ModInfo.ID + ".config.title" :
ModInfo.ID + ".config" + (category.isEmpty() ? "" : "." + category) + ".title")
);
this.parent = parent;
this.category = category;
}
@Override
public void tick() { super.tick(); }
//==================//
// menu UI creation //
//==================//
@Override
protected void init()
{
super.init();
if (!this.reload)
{
ConfigHandler.INSTANCE.configFileHandler.loadFromFile();
}
// Changelog button
if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get()
// we only have changelogs for stable builds
&& !ModInfo.IS_DEV_BUILD)
{
this.addBtn(new TexturedButtonWidget(
// Where the button is on the screen
this.width - 28, this.height - 28,
// Width and height of the button
20, 20,
// texture UV Offset
0, 0,
// Some texture stuff
0,
#if MC_VER < MC_1_21_1
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
#elif MC_VER <= MC_1_21_10
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
#else
Identifier.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
#endif
20, 20,
// Create the button and tell it where to go
(buttonWidget) -> {
ChangelogScreen changelogScreen = new ChangelogScreen(this);
if (changelogScreen.usable)
{
Objects.requireNonNull(this.minecraft).setScreen(changelogScreen);
}
else
{
LOGGER.warn("Changelog was not able to open");
}
},
// Add a title to the button
Translatable(ModInfo.ID + ".updater.title")
));
}
// back button
this.addBtn(MakeBtn(Translatable("distanthorizons.general.back"),
(this.width / 2) - 154, this.height - 28,
ClassicConfigGUI.ConfigScreenConfigs.OPTION_FIELD_WIDTH, ClassicConfigGUI.ConfigScreenConfigs.OPTION_FIELD_HEIGHT,
(button) ->
{
ConfigHandler.INSTANCE.configFileHandler.loadFromFile();
Objects.requireNonNull(this.minecraft).setScreen(this.parent);
}));
// done/close button
this.doneButton = this.addBtn(
MakeBtn(Translatable("distanthorizons.general.done"),
(this.width / 2) + 4, this.height - 28,
ClassicConfigGUI.ConfigScreenConfigs.OPTION_FIELD_WIDTH, ClassicConfigGUI.ConfigScreenConfigs.OPTION_FIELD_HEIGHT,
(button) ->
{
ConfigHandler.INSTANCE.configFileHandler.saveToFile();
Objects.requireNonNull(this.minecraft).setScreen(this.parent);
}));
this.configListWidget = new ClassicConfigGUI.ConfigListWidget(this.minecraft, this.width * 2, this.height, 32, 32, 25);
#if MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
if (this.minecraft != null && this.minecraft.level != null)
{
this.configListWidget.setRenderBackground(false);
}
#endif
this.addWidget(this.configListWidget);
for (AbstractConfigBase<?> configEntry : ConfigHandler.INSTANCE.configBaseList)
{
try
{
if (configEntry.getCategory().matches(this.category)
&& configEntry.getAppearance().showInGui)
{
this.addMenuItem(configEntry);
}
}
catch (Exception e)
{
String message = "ERROR: Failed to show [" + configEntry.getNameAndCategory() + "], error: [" + e.getMessage() + "]";
if (configEntry.get() != null)
{
message += " with the value [" + configEntry.get() + "] with type [" + configEntry.getType() + "]";
}
LOGGER.error(message, e);
}
}
ClassicConfigGUI.CONFIG_CORE_INTERFACE.onScreenChangeListenerList.forEach((listener) -> listener.run());
}
private void addMenuItem(AbstractConfigBase<?> configEntry)
{
trySetupConfigEntry(configEntry);
if (this.tryCreateInputField(configEntry)) return;
if (this.tryCreateCategoryButton(configEntry)) return;
if (this.tryCreateButton(configEntry)) return;
if (this.tryCreateComment(configEntry)) return;
if (this.tryCreateSpacer(configEntry)) return;
if (this.tryCreateLinkedEntry(configEntry)) return;
LOGGER.warn("Config [" + configEntry.getNameAndCategory() + "] failed to show. Please try something like changing its type.");
}
private static void trySetupConfigEntry(AbstractConfigBase<?> configMenuOption)
{
configMenuOption.guiValue = new ConfigGuiInfo();
Class<?> configValueClass = configMenuOption.getType();
if (configMenuOption instanceof ConfigEntry)
{
ConfigEntry<?> configEntry = (ConfigEntry<?>) configMenuOption;
if (configValueClass == Integer.class)
{
setupTextMenuOption(configEntry, Integer::parseInt, ClassicConfigGUI.INTEGER_ONLY_REGEX, true);
}
else if (configValueClass == Double.class)
{
setupTextMenuOption(configEntry, Double::parseDouble, ClassicConfigGUI.DECIMAL_ONLY_REGEX, false);
}
else if (configValueClass == Float.class)
{
setupTextMenuOption(configEntry, Float::parseFloat, ClassicConfigGUI.DECIMAL_ONLY_REGEX, false);
}
else if (configValueClass == String.class || configValueClass == List.class)
{
// For string or list
setupTextMenuOption(configEntry, String::length, null, true);
}
else if (configValueClass == Boolean.class)
{
ConfigEntry<Boolean> booleanConfigEntry = (ConfigEntry<Boolean>) configEntry;
setupBooleanMenuOption(booleanConfigEntry);
}
else if (configValueClass.isEnum())
{
ConfigEntry<Enum<?>> enumConfigEntry = (ConfigEntry<Enum<?>>) configEntry;
Class<? extends Enum<?>> configEnumClass = (Class<? extends Enum<?>>) configValueClass;
setupEnumMenuOption(enumConfigEntry, configEnumClass);
}
else
{
LOGGER.error("No definition for config with type: [" + configValueClass.getName() + "], for config: [" + configMenuOption.name + "].");
}
}
}
private static void setupTextMenuOption(AbstractConfigBase<?> configMenuOption, Function<String, Number> parsingFunc, @Nullable Pattern pattern, boolean cast)
{
final ConfigGuiInfo configGuiInfo = ((ConfigGuiInfo) configMenuOption.guiValue);
configGuiInfo.tooltipFunction =
(editBox, button) ->
(stringValue) ->
{
boolean isNumber = (pattern != null);
stringValue = stringValue.trim();
if (!(stringValue.isEmpty() || !isNumber || pattern.matcher(stringValue).matches()))
{
return false;
}
Number numberValue = configMenuOption.typeIsFloatingPointNumber() ? 0.0 : 0; // different default values are needed so implicit casting works correctly (if not done casting from 0 (an int) to a double will cause an exception)
configGuiInfo.errorMessage = null;
if (isNumber
&& !stringValue.isEmpty()
&& !stringValue.equals("-")
&& !stringValue.equals("."))
{
ConfigEntry<Number> numberConfigEntry = (ConfigEntry<Number>) configMenuOption;
try
{
numberValue = parsingFunc.apply(stringValue);
}
catch (Exception e)
{
numberValue = null;
}
EConfigValidity validity = numberConfigEntry.getValidity(numberValue);
switch (validity)
{
case VALID:
configGuiInfo.errorMessage = null;
break;
case NUMBER_TOO_LOW:
configGuiInfo.errorMessage = TextOrTranslatable("§cMinimum length is " + numberConfigEntry.getMin());
break;
case NUMBER_TOO_HIGH:
configGuiInfo.errorMessage = TextOrTranslatable("§cMaximum length is " + numberConfigEntry.getMax());
break;
case INVALID:
configGuiInfo.errorMessage = TextOrTranslatable("§cValue is invalid");
break;
}
}
editBox.setTextColor(((ConfigEntry<Number>) configMenuOption).getValidity(numberValue) == EConfigValidity.VALID ? 0xFFFFFFFF : 0xFFFF7777); // white and red
if (configMenuOption.getType() == String.class
|| configMenuOption.getType() == List.class)
{
((ConfigEntry<String>) configMenuOption).uiSetWithoutSaving(stringValue);
}
else if (((ConfigEntry<Number>) configMenuOption).getValidity(numberValue) == EConfigValidity.VALID)
{
if (!cast)
{
((ConfigEntry<Number>) configMenuOption).uiSetWithoutSaving(numberValue);
}
else
{
((ConfigEntry<Number>) configMenuOption).uiSetWithoutSaving(numberValue != null ? numberValue.intValue() : 0);
}
}
return true;
};
}
private static void setupBooleanMenuOption(ConfigEntry<Boolean> booleanConfigEntry)
{
// For boolean
Function<Object, Component> func = value -> Translatable("distanthorizons.general." + ((Boolean) value ? "true" : "false")).withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
final ConfigGuiInfo configGuiInfo = ((ConfigGuiInfo) booleanConfigEntry.guiValue);
configGuiInfo.buttonOptionMap =
new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(
(button) ->
{
button.active = !booleanConfigEntry.apiIsOverriding();
booleanConfigEntry.uiSetWithoutSaving(!booleanConfigEntry.get());
button.setMessage(func.apply(booleanConfigEntry.get()));
}, func);
}
private static void setupEnumMenuOption(ConfigEntry<Enum<?>> enumConfigEntry, Class<? extends Enum<?>> enumClass)
{
List<Enum<?>> enumList = Arrays.asList(enumClass.getEnumConstants());
final ConfigGuiInfo configGuiInfo = ((ConfigGuiInfo) enumConfigEntry.guiValue);
Function<Object, Component> getEnumTranslatableFunc = (value) -> Translatable(TRANSLATION_PREFIX + "enum." + enumClass.getSimpleName() + "." + enumConfigEntry.get().toString());
configGuiInfo.buttonOptionMap =
new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(
(button) ->
{
// get the currently selected enum and enum index
int startingIndex = enumList.indexOf(enumConfigEntry.get());
Enum<?> enumValue = enumList.get(startingIndex);
boolean shiftPressed =
InputConstants.isKeyDown(MC_CLIENT.getGlfwWindowId(), GLFW.GLFW_KEY_LEFT_SHIFT)
|| InputConstants.isKeyDown(MC_CLIENT.getGlfwWindowId(), GLFW.GLFW_KEY_RIGHT_SHIFT);
// move forward or backwards depending on if the shift key is pressed
int index = shiftPressed ? startingIndex - 1 : startingIndex + 1;
// wrap around to the other side of the array when necessary
if (index >= enumList.size())
{
index = 0;
}
else if (index < 0)
{
index = enumList.size() - 1;
}
// walk through the enums to find the next selectable one
while (index != startingIndex)
{
enumValue = enumList.get(index);
if (!AnnotationUtil.doesEnumHaveAnnotation(enumValue, DisallowSelectingViaConfigGui.class))
{
// this enum shouldn't be selectable via the UI,
// skip it
break;
}
// move forward or backwards depending on if the shift key is pressed
index = shiftPressed ? index - 1 : index + 1;
// wrap around to the other side of the array when necessary
if (index >= enumList.size())
{
index = 0;
}
else if (index < 0)
{
index = enumList.size() - 1;
}
}
if (index == startingIndex)
{
// one of the enums should be selectable, this is a programmer error
enumValue = enumList.get(startingIndex);
LOGGER.warn("Enum [" + enumValue.getClass() + "] doesn't contain any values that should be selectable via the UI, sticking to the currently selected value [" + enumValue + "].");
}
enumConfigEntry.uiSetWithoutSaving(enumValue);
button.active = !enumConfigEntry.apiIsOverriding();
button.setMessage(getEnumTranslatableFunc.apply(enumConfigEntry.get()));
}, getEnumTranslatableFunc);
}
private boolean tryCreateInputField(AbstractConfigBase<?> configBase)
{
final ConfigGuiInfo configGuiInfo = ((ConfigGuiInfo) configBase.guiValue);
if (configBase instanceof ConfigEntry)
{
ConfigEntry configEntry = (ConfigEntry) configBase;
//==============//
// reset button //
//==============//
Button.OnPress btnAction = (button) ->
{
configEntry.uiSetWithoutSaving(configEntry.getDefaultValue());
this.reload = true;
Objects.requireNonNull(this.minecraft).setScreen(this);
};
int resetButtonPosX = this.width
- ClassicConfigGUI.ConfigScreenConfigs.RESET_BUTTON_WIDTH
- ClassicConfigGUI.ConfigScreenConfigs.SPACE_FROM_RIGHT_SCREEN;
int resetButtonPosZ = 0;
Button resetButton = MakeBtn(
Translatable("distanthorizons.general.reset").withStyle(ChatFormatting.RED),
resetButtonPosX, resetButtonPosZ,
ClassicConfigGUI.ConfigScreenConfigs.RESET_BUTTON_WIDTH, ClassicConfigGUI.ConfigScreenConfigs.RESET_BUTTON_HEIGHT,
btnAction);
if (configEntry.apiIsOverriding())
{
resetButton.active = false;
resetButton.setMessage(Translatable("distanthorizons.general.apiOverride").withStyle(ChatFormatting.DARK_GRAY));
}
else
{
resetButton.active = true;
}
//==============//
// option field //
//==============//
Component textComponent = this.GetTranslatableTextComponentForConfig(configEntry);
int optionFieldPosX = this.width
- ClassicConfigGUI.ConfigScreenConfigs.SPACE_FROM_RIGHT_SCREEN
- ClassicConfigGUI.ConfigScreenConfigs.RESET_BUTTON_WIDTH
- ClassicConfigGUI.ConfigScreenConfigs.BUTTON_WIDTH_SPACING
- ClassicConfigGUI.ConfigScreenConfigs.OPTION_FIELD_WIDTH;
int optionFieldPosZ = 0;
if (configGuiInfo.buttonOptionMap != null)
{
// enum/multi option input button
Map.Entry<Button.OnPress, Function<Object, Component>> widget = configGuiInfo.buttonOptionMap;
if (configEntry.getType().isEnum())
{
widget.setValue((value) -> Translatable(TRANSLATION_PREFIX + "enum." + configEntry.getType().getSimpleName() + "." + configEntry.get().toString()));
}
Button button = MakeBtn(
widget.getValue().apply(configEntry.get()),
optionFieldPosX, optionFieldPosZ,
ClassicConfigGUI.ConfigScreenConfigs.OPTION_FIELD_WIDTH, ClassicConfigGUI.ConfigScreenConfigs.CATEGORY_BUTTON_HEIGHT,
widget.getKey());
// deactivate the button if the API is overriding it
button.active = !configEntry.apiIsOverriding();
this.configListWidget.addButton(this, configEntry,
button,
resetButton,
null,
textComponent);
return true;
}
else
{
// text box input
EditBox widget = new EditBox(this.font,
optionFieldPosX, optionFieldPosZ,
ClassicConfigGUI.ConfigScreenConfigs.OPTION_FIELD_WIDTH - 4, ClassicConfigGUI.ConfigScreenConfigs.CATEGORY_BUTTON_HEIGHT,
Translatable(""));
widget.setMaxLength(3_000_000); // hopefully 3 million characters should be enough for any normal use-case, lol
widget.insertText(String.valueOf(configEntry.get()));
Predicate<String> processor = configGuiInfo.tooltipFunction.apply(widget, this.doneButton);
#if MC_VER <= MC_1_21_11
widget.setFilter(processor);
#else
widget.setResponder(processor::test);
#endif
this.configListWidget.addButton(this, configEntry, widget, resetButton, null, textComponent);
return true;
}
}
return false;
}
private boolean tryCreateCategoryButton(AbstractConfigBase<?> configType)
{
if (configType instanceof ConfigCategory)
{
ConfigCategory configCategory = (ConfigCategory) configType;
Component textComponent = this.GetTranslatableTextComponentForConfig(configCategory);
int categoryPosX = this.width - ClassicConfigGUI.ConfigScreenConfigs.CATEGORY_BUTTON_WIDTH - ClassicConfigGUI.ConfigScreenConfigs.SPACE_FROM_RIGHT_SCREEN;
int categoryPosZ = this.height - ClassicConfigGUI.ConfigScreenConfigs.CATEGORY_BUTTON_HEIGHT; // Note: the posZ value here seems to be ignored
Button widget = MakeBtn(textComponent,
categoryPosX, categoryPosZ,
ClassicConfigGUI.ConfigScreenConfigs.CATEGORY_BUTTON_WIDTH, ClassicConfigGUI.ConfigScreenConfigs.CATEGORY_BUTTON_HEIGHT,
((button) ->
{
ConfigHandler.INSTANCE.configFileHandler.saveToFile();
Objects.requireNonNull(this.minecraft).setScreen(ClassicConfigGUI.getScreen(this, configCategory.getDestination()));
}));
this.configListWidget.addButton(this, configType, widget, null, null, null);
return true;
}
return false;
}
private boolean tryCreateButton(AbstractConfigBase<?> configType)
{
if (configType instanceof ConfigUIButton)
{
ConfigUIButton configUiButton = (ConfigUIButton) configType;
Component textComponent = this.GetTranslatableTextComponentForConfig(configUiButton);
int buttonPosX = this.width - ClassicConfigGUI.ConfigScreenConfigs.CATEGORY_BUTTON_WIDTH - ClassicConfigGUI.ConfigScreenConfigs.SPACE_FROM_RIGHT_SCREEN;
Button widget = MakeBtn(textComponent,
buttonPosX, this.height - 28,
ClassicConfigGUI.ConfigScreenConfigs.CATEGORY_BUTTON_WIDTH, ClassicConfigGUI.ConfigScreenConfigs.CATEGORY_BUTTON_HEIGHT,
(button) -> ((ConfigUIButton) configType).runAction());
this.configListWidget.addButton(this, configType, widget, null, null, null);
return true;
}
return false;
}
private boolean tryCreateComment(AbstractConfigBase<?> configType)
{
if (configType instanceof ConfigUIComment)
{
ConfigUIComment configUiComment = (ConfigUIComment) configType;
Component textComponent = this.GetTranslatableTextComponentForConfig(configUiComment);
if (configUiComment.parentConfigPath != null)
{
textComponent = Translatable(TRANSLATION_PREFIX + configUiComment.parentConfigPath);
}
this.configListWidget.addButton(this, configType, null, null, null, textComponent);
return true;
}
return false;
}
private boolean tryCreateSpacer(AbstractConfigBase<?> configType)
{
if (configType instanceof ConfigUISpacer)
{
Button spacerButton = MakeBtn(Translatable("distanthorizons.general.spacer"),
10, 10, // having too small of a size causes division by 0 errors in older MC versions (IE 1.20.1)
1, 1,
(button) -> { });
spacerButton.visible = false;
this.configListWidget.addButton(this, configType, spacerButton, null, null, null);
return true;
}
return false;
}
private boolean tryCreateLinkedEntry(AbstractConfigBase<?> configType)
{
if (configType instanceof ConfigUiLinkedEntry)
{
this.addMenuItem(((ConfigUiLinkedEntry) configType).get());
return true;
}
return false;
}
private Component GetTranslatableTextComponentForConfig(AbstractConfigBase<?> configType)
{ return Translatable(TRANSLATION_PREFIX + configType.getNameAndCategory()); }
//===========//
// rendering //
//===========//
@Override
#if MC_VER < MC_1_20_1
public void render(PoseStack matrices, int mouseX, int mouseY, float delta)
#elif MC_VER <= MC_1_21_11
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
#else
public void extractRenderState(GuiGraphicsExtractor matrices, int mouseX, int mouseY, float delta)
#endif
{
#if MC_VER < MC_1_20_2 // 1.20.2 now enables this by default in the `this.list.render` function
this.renderBackground(matrices);
#elif MC_VER <= MC_1_21_11
super.render(matrices, mouseX, mouseY, delta);
#else
super.extractRenderState(matrices, mouseX, mouseY, delta);
#endif
// Render buttons
#if MC_VER <= MC_1_21_11
this.configListWidget.render(matrices, mouseX, mouseY, delta);
#else
this.configListWidget.extractRenderState(matrices, mouseX, mouseY, delta);
#endif
// Render config title
this.DhDrawCenteredString(matrices, this.font, this.title,
this.width / 2, 15,
#if MC_VER < MC_1_21_6
0xFFFFFF // RGB white
#else
0xFFFFFFFF // ARGB white
#endif );
// render DH version
this.DhDrawString(matrices, this.font, TextOrLiteral(ModInfo.VERSION), 2, this.height - 10,
#if MC_VER < MC_1_21_6
0xAAAAAA // RGB white
#else
0xFFAAAAAA // ARGB white
#endif );
// If the update is pending, display this message to inform the user that it will apply when the game restarts
if (SelfUpdater.deleteOldJarOnJvmShutdown)
{
this.DhDrawString(matrices, this.font, Translatable(ModInfo.ID + ".updater.waitingForClose"), 4, this.height - 42,
#if MC_VER < MC_1_21_6
0xFFFFFF // RGB white
#else
0xFFFFFFFF // ARGB white
#endif );
}
this.renderTooltip(matrices, mouseX, mouseY, delta);
#if MC_VER < MC_1_20_2
super.render(matrices, mouseX, mouseY, delta);
#endif
}
#if MC_VER < MC_1_20_1
private void renderTooltip(PoseStack matrices, int mouseX, int mouseY, float delta)
#elif MC_VER <= MC_1_21_11
private void renderTooltip(GuiGraphics matrices, int mouseX, int mouseY, float delta)
#else
private void renderTooltip(GuiGraphicsExtractor matrices, int mouseX, int mouseY, float delta)
#endif
{
AbstractWidget hoveredWidget = this.configListWidget.getHoveredButton(mouseX, mouseY);
if (hoveredWidget == null)
{
return;
}
ClassicConfigGUI.DhButtonEntry button = ClassicConfigGUI.DhButtonEntry.BUTTON_BY_WIDGET.get(hoveredWidget);
// A quick fix for tooltips on linked entries
AbstractConfigBase<?> configBase = ConfigUiLinkedEntry.class.isAssignableFrom(button.dhConfigType.getClass()) ?
((ConfigUiLinkedEntry) button.dhConfigType).get() :
button.dhConfigType;
boolean apiOverrideActive = false;
if (configBase instanceof ConfigEntry)
{
apiOverrideActive = ((ConfigEntry<?>) configBase).apiIsOverriding();
}
String key = TRANSLATION_PREFIX + (configBase.category.isEmpty() ? "" : configBase.category + ".") + configBase.getName() + ".@tooltip";
if (apiOverrideActive)
{
key = "distanthorizons.general.disabledByApi.@tooltip";
}
// display the validation error tooltip if present
final ConfigGuiInfo configGuiInfo = ((ConfigGuiInfo) configBase.guiValue);
if (configGuiInfo.errorMessage != null)
{
this.DhRenderTooltip(matrices, this.font, configGuiInfo.errorMessage, mouseX, mouseY);
}
// display the tooltip if present
else if (LANG_WRAPPER.langExists(key))
{
List<Component> list = new ArrayList<>();
String lang = LANG_WRAPPER.getLang(key);
for (String langLine : lang.split("\n"))
{
list.add(TextOrTranslatable(langLine));
}
this.DhRenderComponentTooltip(matrices, this.font, list, mouseX, mouseY);
}
}
//==========//
// shutdown //
//==========//
/** When you close it, it goes to the previous screen and saves */
@Override
public void onClose()
{
ConfigHandler.INSTANCE.configFileHandler.saveToFile();
Objects.requireNonNull(this.minecraft).setScreen(this.parent);
ClassicConfigGUI.CONFIG_CORE_INTERFACE.onScreenChangeListenerList.forEach((listener) -> listener.run());
}
}
@@ -22,6 +22,7 @@ package com.seibel.distanthorizons.common.wrappers.minecraft;
import java.io.File; import java.io.File;
import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.platform.Window;
import com.seibel.distanthorizons.common.wrappers.gui.NativeDialogUtil;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure; import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler; import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
@@ -370,17 +371,28 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
public void crashMinecraft(String errorMessage, Throwable exception) public void crashMinecraft(String errorMessage, Throwable exception)
{ {
LOGGER.fatal(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft...", exception); LOGGER.fatal(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft...", exception);
CrashReport report = new CrashReport(errorMessage, exception);
#if MC_VER < MC_1_20_4 // Only crash once the renderer has been set up.
Minecraft.crash(report); // If the renderer hasn't been set up yet crashing MC will
#else // cause a Blaze3D/UI error instead of the error we're trying to send.
MINECRAFT.delayCrash(report); executeOnRenderThread(() ->
#endif {
CrashReport report = new CrashReport(errorMessage, exception);
#if MC_VER < MC_1_20_4
Minecraft.crash(report);
#else
MINECRAFT.delayCrash(report);
#endif
});
} }
@Override @Override
public void executeOnRenderThread(Runnable runnable) { MINECRAFT.execute(runnable); } public void executeOnRenderThread(Runnable runnable) { MINECRAFT.execute(runnable); }
@Override
public void showDialog(String title, String message, String dialogType, String iconType)
{ NativeDialogUtil.showDialog(title, message, dialogType, iconType); }
//endregion //endregion
@@ -30,9 +30,10 @@ import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper; import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
@@ -57,6 +58,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.core.util.math.Vec3d; import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.math.Vec3f; import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
import net.minecraft.client.Camera; import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@@ -97,6 +99,8 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
{ {
public static final MinecraftRenderWrapper INSTANCE = new MinecraftRenderWrapper(); public static final MinecraftRenderWrapper INSTANCE = new MinecraftRenderWrapper();
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
private static final DhLogger LOGGER = new DhLoggerBuilder().build(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final Minecraft MC = Minecraft.getInstance(); private static final Minecraft MC = Minecraft.getInstance();
@@ -364,7 +368,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
public int getTargetFramebuffer() public int getTargetFramebuffer()
{ {
// used so we can access the framebuffer shaders end up rendering to // used so we can access the framebuffer shaders end up rendering to
if (AbstractOptifineAccessor.optifinePresent()) if (OPTIFINE_ACCESSOR != null)
{ {
return this.finalLevelFrameBufferId; return this.finalLevelFrameBufferId;
} }
@@ -23,27 +23,47 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrap
import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.util.profiling.ProfilerFiller;
/**
* @author James Seibel
* @version 11-20-2021
*/
public class ProfilerWrapper implements IProfilerWrapper public class ProfilerWrapper implements IProfilerWrapper
{ {
public ProfilerFiller profiler; public ProfilerFiller profiler;
public ProfilerWrapper(ProfilerFiller newProfiler) { this.profiler = newProfiler; } public ProfilerWrapper(ProfilerFiller newProfiler) { this.profiler = newProfiler; }
/** starts a new section inside the currently running section */
@Override @Override
public void push(String newSection) { this.profiler.push(newSection); } public IProfileBlock push(String newSection)
{
this.profiler.push(newSection);
return new ProfileBlock(this.profiler);
}
/** ends the currently running section and starts a new one */
@Override @Override
public void popPush(String newSection) { this.profiler.popPush(newSection); } public void popPush(String newSection)
{
this.profiler.popPush(newSection);
}
//================//
// helper classes //
//================//
//region
public static class ProfileBlock implements IProfileBlock
{
private final ProfilerFiller profiler;
public ProfileBlock(ProfilerFiller newProfiler) { this.profiler = newProfiler; }
@Override
public void close()
{
this.profiler.pop();
}
}
//endregion
/** ends the currently running section */
@Override
public void pop() { this.profiler.pop(); }
} }
@@ -48,7 +48,7 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
#if MC_VER < MC_1_21_3 #if MC_VER < MC_1_21_3
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
#else #else
import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.coreapi.util.ColorUtil;
#endif #endif
#if MC_VER <= MC_1_21_10 #if MC_VER <= MC_1_21_10
+2 -2
View File
@@ -76,12 +76,12 @@ task deleteResources(type: Delete) {
processResources { processResources {
dependsOn(copyCoreResources) dependsOn(copyCoreResources)
dependsOn(copyCommonLoaderResources) // dependsOn(copyCommonLoaderResources)
} }
tasks.named('runClient') { tasks.named('runClient') {
dependsOn(copyCoreResources) dependsOn(copyCoreResources)
dependsOn(copyCommonLoaderResources) // dependsOn(copyCommonLoaderResources)
finalizedBy(deleteResources) finalizedBy(deleteResources)
} }
@@ -66,6 +66,13 @@ import java.util.concurrent.AbstractExecutorService;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
#endif #endif
#if MC_VER <= MC_1_21_11
#else
import net.fabricmc.fabric.api.client.rendering.v1.level.LevelRenderContext;
import net.fabricmc.fabric.api.client.rendering.v1.level.LevelRenderEvents;
import net.fabricmc.fabric.api.client.rendering.v1.level.LevelTerrainRenderContext;
#endif
import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.platform.InputConstants;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
@@ -91,6 +98,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
private static final MinecraftClientWrapper MC = MinecraftClientWrapper.INSTANCE; private static final MinecraftClientWrapper MC = MinecraftClientWrapper.INSTANCE;
private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class); private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
@Deprecated // just use the static reference
private static final ClientApi clientApi = ClientApi.INSTANCE; private static final ClientApi clientApi = ClientApi.INSTANCE;
HashSet<Integer> previouslyPressKeyCodes = new HashSet<>(); HashSet<Integer> previouslyPressKeyCodes = new HashSet<>();
@@ -108,17 +116,10 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
//========================//
// register mod accessors //
//========================//
SodiumAccessor sodiumAccessor = (SodiumAccessor) ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class);
//==============// //==============//
// chunk events // // chunk events //
//==============// //==============//
//region
// ClientChunkLoadEvent // ClientChunkLoadEvent
ClientChunkEvents.CHUNK_LOAD.register((level, chunk) -> ClientChunkEvents.CHUNK_LOAD.register((level, chunk) ->
@@ -214,12 +215,14 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
return InteractionResult.PASS; return InteractionResult.PASS;
}); });
//endregion
//==============// //==============//
// render event // // render event //
//==============// //==============//
//region
#if MC_VER < MC_1_21_9 #if MC_VER < MC_1_21_9
WorldRenderEvents.AFTER_SETUP.register((renderContext) -> WorldRenderEvents.AFTER_SETUP.register((renderContext) ->
@@ -298,6 +301,27 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
}); });
#endif #endif
#if MC_VER <= MC_1_21_11
#else
LevelRenderEvents.AFTER_TRANSLUCENT_TERRAIN.register((LevelRenderContext levelRenderContext) ->
{
ClientApi.INSTANCE.renderFadeTransparent();
});
LevelRenderEvents.AFTER_OPAQUE_TERRAIN.register((LevelTerrainRenderContext levelTerrainRenderContext) ->
{
ClientApi.INSTANCE.renderFadeOpaque();
});
#endif
//endregion
//=================//
// keyboard events //
//=================//
//region
// Debug keyboard event // Debug keyboard event
// FIXME: Use better hooks so it doesn't trigger key press events in text boxes // FIXME: Use better hooks so it doesn't trigger key press events in text boxes
@@ -309,11 +333,14 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
} }
}); });
//endregion
//==================// //==================//
// networking event // // networking event //
//==================// //==================//
//region
#if MC_VER < MC_1_20_6 #if MC_VER < MC_1_20_6
ClientPlayNetworking.registerGlobalReceiver(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE, (client, handler, buffer, packetSender) -> ClientPlayNetworking.registerGlobalReceiver(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE, (client, handler, buffer, packetSender) ->
@@ -345,6 +372,11 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
ClientApi.INSTANCE.pluginMessageReceived(payload.message()); ClientApi.INSTANCE.pluginMessageReceived(payload.message());
}); });
#endif #endif
//endregion
} }
public void onKeyInput() public void onKeyInput()
@@ -25,7 +25,7 @@ import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.NativeDialogUtil; import com.seibel.distanthorizons.common.wrappers.gui.NativeDialogUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.*; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.*;
@@ -50,8 +50,8 @@ public class MixinChunkSectionsToRender
//===========// //===========//
// Pre MC 26 // // Pre MC 26 //
//===========// //===========//
//regino
#if MC_VER <= MC_1_21_11 #if MC_VER <= MC_1_21_11
//region
#if MC_VER <= MC_1_21_10 #if MC_VER <= MC_1_21_10
// needs to fire at HEAD with a lower than normal order (less than 1000) // needs to fire at HEAD with a lower than normal order (less than 1000)
@@ -78,7 +78,6 @@ public class MixinChunkSectionsToRender
ClientApi.INSTANCE.renderFadeTransparent(); ClientApi.INSTANCE.renderFadeTransparent();
} }
} }
//endregion //endregion
#else #else
@@ -105,22 +104,10 @@ public class MixinChunkSectionsToRender
} }
else if (chunkSectionLayerGroup == ChunkSectionLayerGroup.OPAQUE) else if (chunkSectionLayerGroup == ChunkSectionLayerGroup.OPAQUE)
{ {
ClientApi.INSTANCE.renderFadeTransparent();
ClientApi.INSTANCE.renderLods(); ClientApi.INSTANCE.renderLods();
} }
} }
@Inject(at = @At("RETURN"), method = "renderGroup", order = 800)
private void renderDeferredLayerReturn(ChunkSectionLayerGroup chunkSectionLayerGroup, GpuSampler gpuSampler, CallbackInfo ci)
{
ClientApi.RENDER_STATE.canRenderOrThrow();
if (chunkSectionLayerGroup == ChunkSectionLayerGroup.TRANSLUCENT)
{
ClientApi.INSTANCE.renderFadeOpaque();
}
}
//endregion //endregion
#endif #endif
@@ -0,0 +1,77 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.fabric.mixins.client;
#if MC_VER <= MC_1_21_11
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(Entity.class)
public class MixinGameRenderer {}
#else
import com.mojang.blaze3d.vertex.PoseStack;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.state.OptionsRenderState;
import net.minecraft.client.renderer.state.level.CameraRenderState;
import net.minecraft.util.profiling.ProfilerFiller;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
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;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(GameRenderer.class)
public class MixinGameRenderer
{
// get the modified projection matrix right before it's uploaded to the GPU
@Inject(
method = "renderLevel",
at = @At(
value = "INVOKE",
target = "Lcom/mojang/blaze3d/systems/RenderSystem;setProjectionMatrix(Lcom/mojang/blaze3d/buffers/GpuBufferSlice;Lcom/mojang/blaze3d/ProjectionType;)V",
shift = At.Shift.BEFORE
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void renderLevel(
final DeltaTracker deltaTracker,
final CallbackInfo callback,
final float partialTickTime,
final float cameraEntityPartialTicks,
final LocalPlayer player,
final ProfilerFiller profiler,
final boolean renderBlockOutline,
final OptionsRenderState options,
final CameraRenderState camera,
final Matrix4fc modelViewMatrix,
final Matrix4f projectionMatrix,
final PoseStack poseStack)
{
ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
}
}
#endif
@@ -50,9 +50,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
#elif MC_VER <= MC_1_21_11 #elif MC_VER <= MC_1_21_11
import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.resource.GraphicsResourceAllocator; import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper; import net.minecraft.client.Camera;
import net.minecraft.client.DeltaTracker; import net.minecraft.client.DeltaTracker;
import net.minecraft.client.renderer.chunk.ChunkSectionsToRender; import net.minecraft.client.renderer.chunk.ChunkSectionsToRender;
import org.joml.Matrix4f;
import org.joml.Matrix4fc; import org.joml.Matrix4fc;
import org.joml.Vector4f; import org.joml.Vector4f;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -60,7 +61,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
#else #else
import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.resource.GraphicsResourceAllocator; import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import net.minecraft.client.DeltaTracker; import net.minecraft.client.DeltaTracker;
import net.minecraft.client.renderer.chunk.ChunkSectionsToRender; import net.minecraft.client.renderer.chunk.ChunkSectionsToRender;
import org.joml.Matrix4fc; import org.joml.Matrix4fc;
@@ -71,6 +71,7 @@ import net.minecraft.client.renderer.state.level.CameraRenderState;
#endif #endif
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter; import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.api.internal.ClientApi;
@@ -235,33 +236,11 @@ public class MixinLevelRenderer
CallbackInfo callback) CallbackInfo callback)
{ {
ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrix); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrix);
ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(camera.projectionMatrix);
ClientApi.RENDER_STATE.partialTickTime = MinecraftRenderWrapper.INSTANCE.getPartialTickTime(); ClientApi.RENDER_STATE.partialTickTime = MinecraftRenderWrapper.INSTANCE.getPartialTickTime();
} }
@Inject(
method = "addMainPass(Lcom/mojang/blaze3d/framegraph/FrameGraphBuilder;Lnet/minecraft/client/renderer/culling/Frustum;Lorg/joml/Matrix4fc;Lcom/mojang/blaze3d/buffers/GpuBufferSlice;ZLnet/minecraft/client/renderer/state/level/LevelRenderState;Lnet/minecraft/client/DeltaTracker;Lnet/minecraft/util/profiling/ProfilerFiller;Lnet/minecraft/client/renderer/chunk/ChunkSectionsToRender;)V",
at = @At(
value = "RETURN",
target = "Lcom/mojang/blaze3d/framegraph/FramePass;executes(Ljava/lang/Runnable;)V",
remap = false
)
)
public void addMainPass(
CallbackInfo ci)
{
// only crash during development
if (ModInfo.IS_DEV_BUILD)
{
ClientApi.RENDER_STATE.canRenderOrThrow();
}
ClientApi.INSTANCE.renderLods();
}
#endif #endif
//endregion //endregion
@@ -1,5 +1,16 @@
package com.seibel.distanthorizons.fabric.mixins.client; package com.seibel.distanthorizons.fabric.mixins.client;
#if MC_VER <= MC_1_21_10
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(Entity.class)
public class MixinSharedConstants
{ /* not present in older MC versions */ }
#else
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.SharedConstants; import net.minecraft.SharedConstants;
import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.*;
@@ -16,8 +27,35 @@ public abstract class MixinSharedConstants
@Inject(method = "<clinit>", at = @At("TAIL")) @Inject(method = "<clinit>", at = @At("TAIL"))
private static void setIsRunningInIde(CallbackInfo ci) private static void setIsRunningInIde(CallbackInfo ci)
{ {
// run extra validation for dev builds DhLogger logger = new DhLoggerBuilder().name("SharedConstants").build();
// setting IS_RUNNING_IN_IDE to true enables
// additional validation on Mojang's side which
// helps catch errors when developing for Blaze3D
boolean irisPresent;
#if MC_VER <= MC_1_21_11
IS_RUNNING_IN_IDE = ModInfo.IS_DEV_BUILD; IS_RUNNING_IN_IDE = ModInfo.IS_DEV_BUILD;
#else
try
{
// Iris has a bug for MC 26 and newer where it doesn't have
// a "sampler1" bound, causing a renderer crash if
// Blaze3D validation is enabled (which is enabled by if
// IS_RUNNING_IN_IDE is true)
ModInfo.class.getClassLoader().loadClass("net.irisshaders.iris.api.v0.IrisApi");
irisPresent = true;
}
catch (ClassNotFoundException ignore)
{
irisPresent = false;
}
IS_RUNNING_IN_IDE = ModInfo.IS_DEV_BUILD && !irisPresent;
#endif
logger.info("Setting Minecraft's SharedConstants.IS_RUNNING_IN_IDE to ["+IS_RUNNING_IN_IDE+"]");
} }
} }
#endif
@@ -16,6 +16,7 @@
"client.MixinClientPacketListener", "client.MixinClientPacketListener",
"client.MixinDebugScreenOverlay", "client.MixinDebugScreenOverlay",
"client.MixinFogRenderer", "client.MixinFogRenderer",
"client.MixinGameRenderer",
"client.MixinLevelRenderer", "client.MixinLevelRenderer",
"client.MixinChunkSectionsToRender", "client.MixinChunkSectionsToRender",
"client.MixinLightTexture", "client.MixinLightTexture",
+1 -1
View File
@@ -19,7 +19,7 @@
"license": "LGPL-3", "license": "LGPL-3",
"icon": "assets/distanthorizons/icon.png", "icon": "assets/distanthorizons/icon.png",
"accessWidener": "distanthorizons.accesswidener", "accessWidener": "${accessWidenerVersion}.distanthorizons.accesswidener",
"environment": "*", "environment": "*",
"entrypoints": { "entrypoints": {
+1 -1
View File
@@ -39,7 +39,7 @@ task deleteResources(type: Delete) {
tasks.register('copyAllResources') { tasks.register('copyAllResources') {
dependsOn(copyCoreResources) dependsOn(copyCoreResources)
dependsOn(copyCommonLoaderResources) // dependsOn(copyCommonLoaderResources)
} }
processResources { processResources {
+5 -3
View File
@@ -1,10 +1,12 @@
{ {
"pack": { "pack": {
"pack_format": 7, "pack_format": 64,
"supported_formats": { "supported_formats": {
"min_inclusive": 16, "min_inclusive": 64,
"max_inclusive": 90000 "max_inclusive": 90000
}, },
"description": "Distant Horizons" "description": "Distant Horizons",
"min_format": 64,
"max_format": 90000
} }
} }
+6 -5
View File
@@ -5,7 +5,8 @@ org.gradle.caching=true
# Mod Info # Mod Info
mod_name=DistantHorizons mod_name=DistantHorizons
mod_version=3.0.0-b-dev api_name=DistantHorizonsApi
mod_version=3.0.1-b
api_version=6.0.0 api_version=6.0.0
maven_group=com.seibel.distanthorizons maven_group=com.seibel.distanthorizons
mod_readable_name=Distant Horizons mod_readable_name=Distant Horizons
@@ -13,8 +14,8 @@ mod_description=This mod generates and renders simplified terrain beyond the nor
# Note: In forge's mods.toml this is hard coded because Architectury throws an error with setting it as a variable # Note: In forge's mods.toml this is hard coded because Architectury throws an error with setting it as a variable
mod_authors=["James Seibel", "Leonardo Amato", "Cola", "coolGi", "Ran", "Leetom", "pshsh"] mod_authors=["James Seibel", "Leonardo Amato", "Cola", "coolGi", "Ran", "Leetom", "pshsh"]
mod_homepage=https://modrinth.com/mod/distanthorizons mod_homepage=https://modrinth.com/mod/distanthorizons
mod_source=https://gitlab.com/jeseibel/distant-horizons mod_source=https://gitlab.com/distant-horizons-team/distant-horizons/
mod_issues=https://gitlab.com/jeseibel/distant-horizons/-/issues mod_issues=https://gitlab.com/distant-horizons-team/distant-horizons/-/issues
mod_discord=https://discord.gg/xAB8G4cENx mod_discord=https://discord.gg/xAB8G4cENx
# Global Plugin Versions # Global Plugin Versions
@@ -46,7 +47,7 @@ versionStr=
# This defines what MC version Intellij will use for the preprocessor # This defines what MC version Intellij will use for the preprocessor
# and what version is used automatically by build and run commands # and what version is used automatically by build and run commands
mcVer=1.26.1 mcVer=26.1.2
# Defines the maximum amount of memory Minecraft is allowed when run in a development environment # Defines the maximum amount of memory Minecraft is allowed when run in a development environment
#minecraftMemoryJavaArg="-Xmx4G" minecraftMemoryJavaArg=-Xmx6G
+2 -2
View File
@@ -29,12 +29,12 @@ task deleteResources(type: Delete) {
processResources { processResources {
dependsOn(copyCoreResources) dependsOn(copyCoreResources)
dependsOn(copyCommonLoaderResources) // dependsOn(copyCommonLoaderResources)
} }
tasks.named('runClient') { tasks.named('runClient') {
dependsOn(copyCoreResources) dependsOn(copyCoreResources)
dependsOn(copyCommonLoaderResources) // dependsOn(copyCommonLoaderResources)
finalizedBy(deleteResources) finalizedBy(deleteResources)
} }
@@ -228,8 +228,10 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
{ {
#if MC_VER < MC_1_21_9 #if MC_VER < MC_1_21_9
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, (ClientLevel)event.getLevel()); ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, (ClientLevel)event.getLevel());
#else #elif MC_VER <= MC_1_21_11
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, event.getLevelRenderer().level); ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, event.getLevelRenderer().level);
#else
// handled via the same mixin as fabric for consistency
#endif #endif
ClientApi.INSTANCE.renderFadeOpaque(); ClientApi.INSTANCE.renderFadeOpaque();
@@ -241,11 +243,11 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
{ {
#if MC_VER < MC_1_21_9 #if MC_VER < MC_1_21_9
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, (ClientLevel)event.getLevel()); ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, (ClientLevel)event.getLevel());
#else #elif MC_VER <= MC_1_21_11
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, event.getLevelRenderer().level); ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, event.getLevelRenderer().level);
#else
// handled via the same mixin as fabric for consistency
#endif #endif
ClientApi.INSTANCE.renderDeferredLodsForShaders();
} }
@SubscribeEvent @SubscribeEvent
@@ -253,8 +255,10 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
{ {
#if MC_VER < MC_1_21_9 #if MC_VER < MC_1_21_9
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, (ClientLevel)event.getLevel()); ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, (ClientLevel)event.getLevel());
#else #elif MC_VER <= MC_1_21_11
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, event.getLevelRenderer().level); ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, event.getLevelRenderer().level);
#else
// handled via the same mixin as fabric for consistency
#endif #endif
@@ -0,0 +1,82 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.neoforge.mixins.client;
#if MC_VER <= MC_1_21_11
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(Entity.class)
public class MixinChunkSectionsToRender
{ /* rendering before was handled via Fabric API events */ }
#else
import com.mojang.blaze3d.textures.GpuSampler;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.chunk.ChunkSectionLayerGroup;
import net.minecraft.client.renderer.chunk.ChunkSectionsToRender;
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(ChunkSectionsToRender.class)
public class MixinChunkSectionsToRender
{
//============//
// post MC 26 //
//============//
//region
#if MC_VER <= MC_1_21_11
#else
// needs to fire at HEAD with a lower than normal order (less than 1000)
// otherwise it will be canceled by Sodium
@Inject(at = @At("HEAD"), method = "renderGroup", order = 800)
private void renderDeferredLayerHead(ChunkSectionLayerGroup chunkSectionLayerGroup, GpuSampler gpuSampler, CallbackInfo ci)
{
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, Minecraft.getInstance().levelRenderer.level);
ClientApi.RENDER_STATE.canRenderOrThrow();
if (chunkSectionLayerGroup == ChunkSectionLayerGroup.TRANSLUCENT)
{
ClientApi.INSTANCE.renderDeferredLodsForShaders();
}
else if (chunkSectionLayerGroup == ChunkSectionLayerGroup.OPAQUE)
{
ClientApi.INSTANCE.renderLods();
}
}
//endregion
#endif
}
#endif
@@ -0,0 +1,77 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.neoforge.mixins.client;
#if MC_VER <= MC_1_21_11
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(Entity.class)
public class MixinGameRenderer {}
#else
import com.mojang.blaze3d.vertex.PoseStack;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.state.OptionsRenderState;
import net.minecraft.client.renderer.state.level.CameraRenderState;
import net.minecraft.util.profiling.ProfilerFiller;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
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;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(GameRenderer.class)
public class MixinGameRenderer
{
// get the modified projection matrix right before it's uploaded to the GPU
@Inject(
method = "renderLevel",
at = @At(
value = "INVOKE",
target = "Lcom/mojang/blaze3d/systems/RenderSystem;setProjectionMatrix(Lcom/mojang/blaze3d/buffers/GpuBufferSlice;Lcom/mojang/blaze3d/ProjectionType;)V",
shift = At.Shift.BEFORE
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void renderLevel(
final DeltaTracker deltaTracker,
final CallbackInfo callback,
final float partialTickTime,
final float cameraEntityPartialTicks,
final LocalPlayer player,
final ProfilerFiller profiler,
final boolean renderBlockOutline,
final OptionsRenderState options,
final CameraRenderState camera,
final Matrix4fc modelViewMatrix,
final Matrix4f projectionMatrix,
final PoseStack poseStack)
{
ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
}
}
#endif
@@ -26,7 +26,7 @@ import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.neoforged.neoforge.client.event.RenderLevelStageEvent; import net.neoforged.neoforge.client.event.RenderLevelStageEvent;
import org.joml.Matrix4f; import org.joml.Matrix4f;
#else #elif MC_VER <= MC_1_21_11
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.chunk.ChunkSectionsToRender; import net.minecraft.client.renderer.chunk.ChunkSectionsToRender;
@@ -35,6 +35,25 @@ import net.minecraft.client.DeltaTracker;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.LevelRenderer;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector4f;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
#else
import com.mojang.blaze3d.textures.GpuSampler;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.chunk.ChunkSectionLayerGroup;
import net.minecraft.client.renderer.chunk.ChunkSectionsToRender;
import net.minecraft.client.Camera;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.state.level.CameraRenderState; import net.minecraft.client.renderer.state.level.CameraRenderState;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.joml.Matrix4fc; import org.joml.Matrix4fc;
@@ -201,40 +220,11 @@ public class MixinLevelRenderer
CallbackInfo callback) CallbackInfo callback)
{ {
ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrix); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrix);
ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(camera.projectionMatrix);
ClientApi.RENDER_STATE.partialTickTime = MinecraftRenderWrapper.INSTANCE.getPartialTickTime(); ClientApi.RENDER_STATE.partialTickTime = MinecraftRenderWrapper.INSTANCE.getPartialTickTime();
} }
@Inject(
method = "addMainPass(Lcom/mojang/blaze3d/framegraph/FrameGraphBuilder;Lnet/minecraft/client/renderer/culling/Frustum;Lorg/joml/Matrix4fc;Lcom/mojang/blaze3d/buffers/GpuBufferSlice;ZLnet/minecraft/client/renderer/state/level/LevelRenderState;Lnet/minecraft/client/DeltaTracker;Lnet/minecraft/util/profiling/ProfilerFiller;Lnet/minecraft/client/renderer/chunk/ChunkSectionsToRender;)V",
at = @At(
value = "RETURN",
target = "Lcom/mojang/blaze3d/framegraph/FramePass;executes(Ljava/lang/Runnable;)V",
remap = false
)
)
public void addMainPass(
CallbackInfo ci)
{
// only crash during development
if (ModInfo.IS_DEV_BUILD)
{
try
{
ClientApi.RENDER_STATE.canRenderOrThrow();
}
catch (IllegalStateException e)
{
return;
}
}
ClientApi.INSTANCE.renderLods();
}
#endif #endif
//endregion //endregion
@@ -15,6 +15,8 @@
"client.MixinClientPacketListener", "client.MixinClientPacketListener",
"client.MixinDebugScreenOverlay", "client.MixinDebugScreenOverlay",
"client.MixinFogRenderer", "client.MixinFogRenderer",
"client.MixinChunkSectionsToRender",
"client.MixinGameRenderer",
"client.MixinLevelRenderer", "client.MixinLevelRenderer",
"client.MixinLightTexture", "client.MixinLightTexture",
"client.MixinMinecraft", "client.MixinMinecraft",
+1 -1
View File
@@ -4,7 +4,7 @@ minecraft_version=1.21.3
parchment_version=1.21:2024.07.28 parchment_version=1.21:2024.07.28
compatible_minecraft_versions=["1.21.3"] compatible_minecraft_versions=["1.21.3"]
accessWidenerVersion=1_21_3 accessWidenerVersion=1_21_3
builds_for=neoforge,fabric builds_for=fabric,neoforge
# forge is broken due to gradle/build script issues # forge is broken due to gradle/build script issues
# Netty # Netty
+1 -1
View File
@@ -4,7 +4,7 @@ minecraft_version=1.21.4
parchment_version=1.21:2024.07.28 parchment_version=1.21:2024.07.28
compatible_minecraft_versions=["1.21.4"] compatible_minecraft_versions=["1.21.4"]
accessWidenerVersion=1_21_4 accessWidenerVersion=1_21_4
builds_for=neoforge,fabric builds_for=fabric,neoforge
# forge is broken due to gradle/build script issues # forge is broken due to gradle/build script issues
# Netty # Netty
@@ -1,9 +1,10 @@
# 1.26.1 version # 26.1.2 version
java_version=25 java_version=25
minecraft_version=26.1 minecraft_version=26.1.2
parchment_version=1.21:2024.07.28 parchment_version=1.21:2024.07.28
compatible_minecraft_versions=["26.1"] # version range should be used instead of individual versions due to how NeoForge handles version loading
accessWidenerVersion=1_26_1 compatible_minecraft_versions=["26.1.0", "26.1.2"]
accessWidenerVersion=26_1
builds_for=fabric,neoforge builds_for=fabric,neoforge
# forge is broken due to gradle/build script issues # forge is broken due to gradle/build script issues
@@ -11,17 +12,17 @@ builds_for=fabric,neoforge
netty_version=4.1.97.Final netty_version=4.1.97.Final
# LWJGL # LWJGL
lwjgl_version=3.3.3 lwjgl_version=3.4.1
# Fabric loader # Fabric loader
fabric_loader_version=0.18.5 fabric_loader_version=0.18.5
fabric_api_version=0.144.3+26.1 fabric_api_version=0.145.4+26.1.2
modmenu_version=18.0.0-alpha.8 modmenu_version=18.0.0-alpha.8
starlight_version_fabric= starlight_version_fabric=
phosphor_version_fabric= phosphor_version_fabric=
lithium_version= lithium_version=
sodium_version=mc1.21.11-0.8.7-fabric sodium_version=mc26.1.1-0.8.9-fabric
iris_version=1.10.7+26.1-fabric iris_version=1.10.9+26.1-fabric
bclib_version= bclib_version=
immersive_portals_version= immersive_portals_version=
canvas_version= canvas_version=
@@ -45,7 +46,7 @@ enable_canvas=0
# NeoForge loader # NeoForge loader
forge_version= forge_version=
neoforge_version=1-beta neoforge_version=15-beta
neoforge_version_range=[*,) neoforge_version_range=[*,)
# NeoForge mod versions # NeoForge mod versions