Compare commits

..

175 Commits

Author SHA1 Message Date
James Seibel de33cbce2b Clarify the world gen progress message 2026-05-30 19:44:32 -05:00
James Seibel 2b5f621ff8 Fix old MC version compiling 2026-05-30 16:45:16 -05:00
James Seibel 1681adc10b Add the option for 3 layer clouds 2026-05-30 16:39:00 -05:00
James Seibel f606f2b7c2 remove deprecated items 2026-05-30 11:39:45 -05:00
James Seibel e3f9b66994 reduce GC pressure during LOD loading slightly 2026-05-30 11:32:59 -05:00
James Seibel ec3ff260fe Reduce render event GC pressure 2026-05-30 09:17:46 -05:00
James Seibel fafab30a09 clean up blaze buffer uniform creation 2026-05-22 14:09:47 -05:00
James Seibel 707352ce51 fix native GL instanced generic rendering 2026-05-22 12:51:15 -05:00
James Seibel a9f5dafefe re-add fabric modMenuIntegration 2026-05-22 09:59:59 -05:00
James Seibel 291ffd311b fix renderingEngine lang 2026-05-22 09:59:47 -05:00
James Seibel 0e8c0b459b Fix 1.21.11 and older MC compiling 2026-05-22 09:55:25 -05:00
James Seibel c575a2968b update core 2026-05-22 09:37:45 -05:00
James Seibel 0b297b4cd7 add DhApiBeforeFogRenderEvent 2026-05-22 09:37:12 -05:00
Ran b8c90985ce Merge branch 'translations' into 'main'
Trans :3 lations

See merge request distant-horizons-team/distant-horizons!96
2026-05-21 12:46:52 +00:00
Ran b924576983 Trans :3 lations 2026-05-21 12:46:51 +00:00
James Seibel a8b62b31a1 fix 3+ version number ranges 2026-05-20 17:30:33 -05:00
James Seibel 95b2d5a908 fix pre 26.2 compiling 2026-05-20 17:30:13 -05:00
James Seibel 7d2ccc302d fix render api vs engine enum 2026-05-20 07:28:04 -05:00
James Seibel 1ba1bff859 document openGL interfaces not used on Blaze3D
Also add API logic to determine if DH is handling the rendering natively or using an interpretation layer
2026-05-19 21:52:15 -05:00
James Seibel 9409841c89 fix logger GC warning and running wilderwild in dev 2026-05-19 21:16:22 -05:00
James Seibel 6c4e8021d6 Fix DH world gen not priming CARVER heightmaps
Fixes some world gen mods not having access to the necessary heightmaps
2026-05-19 21:04:51 -05:00
James Seibel 4b1623e8c0 Add world gen getBlockState() Y pos validation 2026-05-19 21:03:56 -05:00
James Seibel a1e88bff70 26.1.2 up fabric API 0.145 -> 0.149 2026-05-19 20:58:03 -05:00
James Seibel f3c20cde30 clean up config menu, remove fake transparency 2026-05-19 19:18:15 -05:00
James Seibel eb601d9276 Fix unit test compiling 2026-05-19 07:26:14 -05:00
James Seibel 17a13993cc Fix holes on LOD borders 2026-05-18 22:24:33 -05:00
James Seibel 16e7254179 add IDhApiLevelWrapper.getBlockColorPreApi() 2026-05-18 19:59:56 -05:00
James Seibel ab055f1a0e fix compiling for MC 1.20 and older 2026-05-18 07:21:34 -05:00
James Seibel 0cb3716dc7 move remaining blaze pipeline methods to wrapper 2026-05-17 18:39:13 -05:00
James Seibel 71e9877808 blaze3D renderPassWrapper 2026-05-17 18:30:36 -05:00
James Seibel f05e424c49 lang wrapper update 2026-05-17 18:27:44 -05:00
James Seibel 646882e1a9 update 26.2 snapshot 5 -> 7 2026-05-17 18:20:27 -05:00
James Seibel 482311fe48 Improve ColorCache resolution errors 2026-05-17 18:04:26 -05:00
James Seibel 97a80ed887 Fix renderingString for disabled dimensions 2026-05-16 19:08:02 -05:00
James Seibel 0e547c80a9 Merge branch 'main' of gitlab.com:distant-horizons-team/distant-horizons 2026-05-16 18:58:46 -05:00
James Seibel b792487b60 fix auto update screen on MC 26.2 2026-05-16 18:55:52 -05:00
James Seibel 7920415d18 Improve incorrect rendering API error handling 2026-05-16 18:25:48 -05:00
James Seibel ada7668c28 fix reverseZDepth uniform name 2026-05-16 17:54:46 -05:00
James Seibel e7a34f9498 fix Blaze3D GL pipelines 2026-05-16 17:03:43 -05:00
James Seibel 2a5c465923 BlazeDhRenderApi handle GL and Vulkan 2026-05-16 16:16:15 -05:00
James Seibel a14a558f0d blaze3D shaders work on both GL and Vulkan 2026-05-16 15:50:25 -05:00
James Seibel 66db5f0df1 add reverse Z java code 2026-05-16 10:49:12 -05:00
James Seibel 2dc4ba20fb fix DH Far Fade renderer name 2026-05-16 10:20:24 -05:00
James Seibel 2f14d7ac27 remove forgix workaround 2026-05-16 10:20:09 -05:00
Vojtěch Šokala 6cc659bda5 Make renderingString show correct value if rendering is disabled for this dimension 2026-05-16 13:33:43 +02:00
James Seibel 206e492e7c use DhScreenUtil.setScreen when possible 2026-05-15 22:28:25 -05:00
James Seibel 09289e72a1 Merge branch 'Vulkan' 2026-05-15 22:25:14 -05:00
James Seibel 7861b63c99 Fix auto update screen not appearing on MC 26.1.2
May also be necessary for old MC versions
2026-05-15 22:13:46 -05:00
James Seibel 965b9c948e update api test method name 2026-05-15 22:03:07 -05:00
James Seibel ae4ca8cd6b Mark vertigo as incompatible 2026-05-15 21:45:58 -05:00
James Seibel 2dec862c3b up api version 6.1.1 -> 7.0.0 2026-05-15 21:41:25 -05:00
James Seibel f9d8073e80 Remove fabric-gametest-api from release 2026-05-15 21:35:25 -05:00
James Seibel 2ca99c29d2 config reset button don't change menu 2026-05-15 18:30:12 -05:00
James Seibel 2e4477b533 fix color tints not clearing with other colors 2026-05-15 18:29:53 -05:00
Vojtěch Šokala b0c7919dda Rewrite 1.12.2 world gen 2026-05-15 20:04:57 +02:00
Vojtěch Šokala 398c14ee96 Merge remote-tracking branch 'origin/main' 2026-05-15 18:59:42 +02:00
Vojtěch Šokala 422e54b488 ChangelogScreen for 1.12.2 2026-05-15 18:59:34 +02:00
James Seibel 36f1c49f49 Add MC Version locking to the config 2026-05-15 07:44:22 -05:00
James Seibel 271f4e8b21 Fix compiling MC 1.16.5+ 2026-05-14 20:52:36 -05:00
James Seibel b164e4646d add 1.12.2 to the build script 2026-05-14 20:13:22 -05:00
James Seibel 14fd5729e2 use ModInfo packet path 2026-05-14 20:11:41 -05:00
James Seibel 7c3e279237 preprocessor cleanup 2026-05-14 20:11:32 -05:00
James Seibel 2884094dee refactoring and cleanup 2026-05-14 07:49:32 -05:00
James Seibel 817c268491 Tint color cleanup 2026-05-14 07:11:44 -05:00
Vojtěch Šokala 071a306f14 Preprocessor cleanup 2026-05-14 13:03:32 +02:00
Vojtěch Šokala c97fea6d0a Fix compile of modern 2026-05-14 07:53:00 +02:00
Vojtěch Šokala d94faf828d Preprocessor cleanup + colored beacons for 1.12.2 2026-05-13 23:59:09 +02:00
Vojtěch Šokala 0d6d4b133e Fix compile of modern 2026-05-13 23:58:25 +02:00
James Seibel 5ab6bfb663 preprocessor cleanup 2026-05-13 07:49:18 -05:00
James Seibel e087dbc878 temp unit test disable 2026-05-12 21:56:30 -05:00
James Seibel 391e96ad3d abstract mod init cleanup 2026-05-12 21:54:03 -05:00
James Seibel fbf812091d MC 1.12.2 refactoring and cleanup 2026-05-12 21:38:07 -05:00
James Seibel 7448483f84 revert option screen name for consistency 2026-05-12 08:02:26 -05:00
James Seibel e3d6e1bcc6 use vanilla fog common 2026-05-12 07:32:57 -05:00
James Seibel fbbcd1b95b fix forgix running on only a single modloader 2026-05-12 07:28:59 -05:00
James Seibel d8e7325044 minor gradle cleanup 2026-05-12 07:28:45 -05:00
James Seibel f17aeca79c add cleanroom run config 2026-05-12 07:28:37 -05:00
James Seibel ac3a223114 add missing licensing headers 2026-05-12 07:28:25 -05:00
James Seibel e4312c2f8b reformat 1.12.2 version prop 2026-05-12 07:28:11 -05:00
James Seibel 17bde631ac Put back jvmdowngrader 2026-05-12 07:02:04 -05:00
James Seibel 64d8f7ee2d update blaze 3d api use 2026-05-11 22:00:07 -05:00
James Seibel d8b3aee9dc temp disable forgix 2026-05-11 22:00:07 -05:00
James Seibel fce94fa4bf update screen mixin update 2026-05-11 22:00:07 -05:00
James Seibel 254d671629 basic mixin updates 2026-05-11 21:58:33 -05:00
James Seibel e66e7e627a disable mod compat code 2026-05-11 21:55:30 -05:00
Vojtěch Šokala 578efbf15f Fix compile of 1.21.6+ 2026-05-08 02:19:45 +02:00
Vojtěch Šokala 8b6bb228e3 Put 26.1.2 back in mcVer 2026-05-08 01:17:19 +02:00
Vojtěch Šokala 611c4606d7 Fix 1.12.2 bugs, fill mcmod.info 2026-05-08 01:15:13 +02:00
Vojtěch Šokala 05bdaf0390 Prevent air transforming into water if waterSubSurfaceBlockReplacementCsv contains invalid resource location 2026-05-07 15:39:14 +02:00
Vojtěch Šokala eb8fcaee36 Fix compilation of modern 2026-05-07 15:34:26 +02:00
Vojtěch Šokala 32a71933d6 Bump forge version on 1.20.1, 1.20.4 for Java 26 support 2026-05-07 15:34:01 +02:00
Vojtěch Šokala a4baf9ca0a make cleanroom work in dev 2026-05-07 12:23:01 +02:00
Vojtěch Šokala 72bfd0a2bb fix color resolve for liquid blocks 2026-05-07 03:39:49 +02:00
Vojtěch Šokala 7ae4a9f460 1.12.2 compiles again 2026-05-06 20:51:08 +02:00
Vojtěch Šokala 9bd6fb0105 merge upstream 2026-05-05 10:00:18 +02:00
James Seibel 1f1024251b up version number 3.0.3 -> 3.0.4 2026-05-04 07:41:48 -05:00
James Seibel fc516a20d5 remove dev from version number 2026-05-03 20:47:00 -05:00
James Seibel 791c2c3426 up api version 6.1.0 -> 6.1.1 2026-05-03 20:47:00 -05:00
James Seibel b00079897a fix blaze generic obj render close on wrong thread 2026-05-03 20:47:00 -05:00
James Seibel 37b73e1d5c Improve stack/GC tracking for GL buffers 2026-05-03 16:45:40 -05:00
James Seibel 4bd1136713 Fix generic buffer cleanup 2026-05-03 16:36:53 -05:00
James Seibel ef98dbd5fd color override API tests 2026-05-02 21:26:33 -05:00
James Seibel 5df0a60b06 add extra optional GLBuffer phantom logging 2026-05-02 21:18:24 -05:00
James Seibel 9feb20eff8 remove unnecessary warning in GLBuffer 2026-05-02 21:18:01 -05:00
James Seibel c9267d61a8 allow toggling tracy via gradle.properties 2026-05-02 15:21:44 -05:00
James Seibel a29e225a80 Fix LOD shading applying incorrectly with Iris 2026-05-02 15:14:33 -05:00
James Seibel ae0f3c2b3b Add oculus api implementation 2026-05-02 12:43:43 -05:00
James Seibel 852ea75449 Update coreSubProjects 2026-05-02 11:45:54 -05:00
James Seibel ab6a5dad2b Revert "Attempt to merge CI changes"
This reverts commit 1a1eaca280.
2026-05-02 11:45:29 -05:00
James Seibel 1a1eaca280 Attempt to merge CI changes 2026-05-02 11:44:09 -05:00
James Seibel 0272f8c57f remove unused manual build scripts 2026-05-02 11:43:13 -05:00
James Seibel cf09358710 fix fog common mixin compiling 2026-05-02 11:04:10 -05:00
James Seibel b5d833fa3d simplify mixin fog common code 2026-05-02 10:57:37 -05:00
James Seibel 329dbe9585 Fix block wrapper null pointer 2026-05-02 10:43:41 -05:00
James Seibel c7ae7f155e move fog common mixin code to common 2026-05-02 10:42:05 -05:00
James Seibel 5f7dbb8662 Fix neoforge debugging 2026-05-02 08:00:14 -05:00
James Seibel ee21548151 comment on why sponge maven can't have fabric 2026-05-01 07:42:53 -05:00
Ran-Mewo ca00125960 exclude FabricMC groups from Sponge repository in dh-loader.gradle 2026-04-30 23:28:29 +10:00
James Seibel 4067264e72 Merge branch 'distant-horizons-fix' 2026-04-29 07:45:29 -05:00
James Seibel 9c2d243ad4 Add position finder debug config 2026-04-29 07:35:24 -05:00
James Seibel de9d8b0d2e Optimize BlockStateWrapper getter 2026-04-28 21:15:07 -05:00
James Seibel 67f4615b34 add backup to texture color getting 2026-04-28 07:46:53 -05:00
James Seibel cd7a130ee4 use camera pos for detail calculations 2026-04-28 07:09:26 -05:00
James Seibel 4d17f7aecf fix null pointer on dedicated server shutdown 2026-04-27 07:48:11 -05:00
James Seibel a59e7500ab Fix wyncraft getting stuck at low LOD quality 2026-04-27 07:27:07 -05:00
James Seibel 40040294e7 up fabric api 1.21.1 version 2026-04-25 15:09:48 -05:00
James Seibel 783e61ec3d Update the readme 2026-04-24 07:47:41 -05:00
James Seibel e09db5d7df up version number 3.0.2 -> 3.0.3 2026-04-24 06:51:44 -05:00
James Seibel 91f9ef3f4b remove dev from the version number 2026-04-24 06:51:09 -05:00
James Seibel d52a3abb14 Add a rough build all parallel batch script 2026-04-23 20:38:51 -05:00
James Seibel 16370b0b6e ignore parallel build folders 2026-04-23 20:38:23 -05:00
James Seibel bfa60b48cf Fix iris transparent blending 2026-04-23 17:54:41 -05:00
James Seibel 50518bfe21 Fix "fog" rendering when underwater with Iris 2026-04-23 17:39:46 -05:00
James Seibel 80e4467829 Fix near clip plane to close with shaders 2026-04-23 17:09:27 -05:00
James Seibel 396315bd05 Fix GC rarely deleting in use GL buffers 2026-04-23 16:57:17 -05:00
James Seibel 7a0fec2c2f Maybe fix a buffer deletion issue? 2026-04-23 07:44:33 -05:00
James Seibel 4afaaa7b12 up api version 6.0.0 -> 6.1.0 2026-04-23 07:42:31 -05:00
James Seibel b057041467 Add more locking and volatile buffer ID checks 2026-04-23 07:16:31 -05:00
James Seibel 33e6ce6376 potential nvidia null VBO pointer crash fix 2026-04-22 22:33:17 -05:00
James Seibel 118ef39c30 Fix flashing when moving over root node boundaries 2026-04-22 18:36:13 -05:00
James Seibel 1013e1c824 Merge branch 'main' of gitlab.com:distant-horizons-team/distant-horizons 2026-04-22 17:15:09 -05:00
James Seibel b0e924c7fe Fix nvidia driver crash 2026-04-22 17:14:50 -05:00
James Seibel 1777acd1d4 remove unused var in ThreadWorldGenParams 2026-04-22 16:54:41 -05:00
s809 8276a862f8 Clean up received payload buffer check a bit 2026-04-23 00:26:37 +05:00
James Seibel 4329acf91d Try fixing rare null pointer in render 2026-04-22 07:51:11 -05:00
James Seibel 72f83b40f7 Fix quad tree unit tests 2026-04-22 07:41:56 -05:00
James Seibel a33eb30a53 fix rare race condition preventing world gen 2026-04-21 22:20:14 -05:00
James Seibel d3e96f50a8 Maybe fix native GL crash due to buffer free 2 2026-04-21 21:40:33 -05:00
James Seibel 3aefeb98b4 Maybe fix native GL crash due to buffer free 2026-04-21 21:37:14 -05:00
James Seibel 3553ff8e60 handle a weird double start issue 2026-04-21 21:25:44 -05:00
James Seibel 945a2c0c5a Fix garbage collector warning not using config 2026-04-21 19:59:23 -05:00
James Seibel 8c7974e216 Improve node out-of-bound logic
This fixes some overlapping rendering issues, fixes LOD generating outside of render distance, and fixes low-detail LODs flashing when moving into previously-explored LODs
2026-04-21 19:50:30 -05:00
James Seibel 37756cd759 Try fixing LOD flashing/stuck low details 2026-04-21 07:48:46 -05:00
James Seibel c60cc4f013 Merge branch 'main' into 'main'
Remove broken TerraFirmaCraft compatibility code

See merge request distant-horizons-team/distant-horizons!86
2026-04-21 11:59:12 +00:00
James Seibel 87cce2e33c Fix LODs loading outside render distance
Fixes !1233
2026-04-19 21:48:33 -05:00
James Seibel 40ada9c186 fix debug wireframe on blaze3D 2026-04-19 16:34:44 -05:00
James Seibel 55fb458266 Maybe reduce memory when using internal world gen 2026-04-19 16:29:27 -05:00
James Seibel 79d2466fa2 Revert "Auto-change rendering backend when Iris is present"
This reverts commit d750e489df.
2026-04-19 15:09:16 -05:00
s809 d750e489df Auto-change rendering backend when Iris is present 2026-04-19 12:57:23 +05:00
James Seibel a206e49b2b up version number 3.0.1 -> 3.0.2 2026-04-18 21:44:33 -05:00
Vojtěch Šokala 9fea29cbb6 Put canvas back 2026-03-17 15:46:00 +01:00
Vojtěch Šokala 7e1e5a56e2 Set back 1.21.11 as default mcVer 2026-03-15 23:41:13 +01:00
Vojtěch Šokala 059293ebe0 Add missing shaders into cleanroom project 2026-03-15 23:31:35 +01:00
Vojtěch Šokala 4f9d4e2a14 Fix compile error 2026-03-15 23:31:13 +01:00
Vojtěch Šokala 6bd3c825c3 Merge branch 'main' of https://gitlab.com/distant-horizons-team/distant-horizons
# Conflicts:
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/InternalServerGenerator.java
2026-03-15 23:27:20 +01:00
Vojtěch Šokala c75595a5e2 [1.12.2] implement pregen command 2026-03-15 23:17:12 +01:00
Vojtěch Šokala 266d463873 fix compile errors 2026-03-15 23:14:54 +01:00
Vojtěch Šokala 73c718c676 [1.12.2] improve config gui to match other versions 2026-03-15 22:13:07 +01:00
Vojtěch Šokala 3df5c04759 Fix issue when MC framebuffer is using renderbuffer for depth 2026-03-15 22:10:03 +01:00
Vojtěch Šokala d72c34a926 Merge branch 'main' of https://gitlab.com/distant-horizons-team/distant-horizons
# Conflicts:
#	common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java
#	common/src/main/java/com/seibel/distanthorizons/common/commands/PregenCommand.java
#	common/src/main/java/com/seibel/distanthorizons/common/render/openGl/GlDhTerrainShaderProgram.java
2026-03-15 15:49:41 +01:00
Vojtěch Šokala 8991338be1 [1.12.2] add support for 3.0.0b 2026-03-15 15:42:08 +01:00
Vojtěch Šokala 6b32ab02d3 Merge branch 'main' of https://gitlab.com/distant-horizons-team/distant-horizons
# Conflicts:
#	common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftGLWrapper.java
#	common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/LightMapWrapper.java
2026-03-11 09:42:18 +01:00
Vojtěch Šokala c5adc3f72a 1.12.2 working in dev 2026-03-11 09:20:32 +01:00
Vojtěch Šokala 1d0d67d215 1.12.2 buildscript 2026-02-20 15:00:13 +01:00
Daniel e5536de44f Remove broken TerraFirmaCraft compatibility code 2025-12-23 19:27:48 -08:00
188 changed files with 8085 additions and 2222 deletions
-19
View File
@@ -1,19 +0,0 @@
**/.git
**/.gitlab
**/.cache
buildAllJars
**/_Misc Files
*.bat
*.md
*.sh
*.txt
coreSubProjects/*.md
coreSubProjects/*.txt
**/.gitignore
**/.gitattributes
**/.gitlab-cy.yml
**/.gitmodules
+2
View File
@@ -25,6 +25,8 @@ hs_err_pid*
Merged/
# Folder created by the buildAll scripts
buildAllJars/
_buildAllJars/
_buildWorkers/
relocate_natives/.venv/
relocate_natives/__pycache__/
+20 -1
View File
@@ -4,6 +4,7 @@ image: eclipse-temurin:25
# all stages need to be defined here
stages:
- translations
- build
- api
- pages
@@ -32,6 +33,9 @@ variables:
build:
stage: build
needs:
- job: translations
artifacts: true
parallel:
matrix:
- MC_VER: [
@@ -41,7 +45,8 @@ build:
"1.19.4", "1.19.2",
"1.18.2",
"1.17.1",
"1.16.5"
"1.16.5",
"1.12.2"
]
script:
# this both runs the unit tests and assembles the code
@@ -101,3 +106,17 @@ pages:
- public
allow_failure: false
extends: .build_java
translations:
stage: translations
needs: []
image: crowdin/cli:latest
script:
- if [ "$CI_COMMIT_BEFORE_SHA" = "0000000000000000000000000000000000000000" ] || git diff --name-only "$CI_COMMIT_BEFORE_SHA" "$CI_COMMIT_SHA" -- coreSubProjects/core/src/main/resources/assets/distanthorizons/lang | grep -q .; then crowdin upload sources; fi
- crowdin download --export-only-approved --skip-untranslated-files
- for f in coreSubProjects/core/src/main/resources/assets/distanthorizons/lang/*.json; do [ -e "$f" ] || continue; sed -i 's/\\\\n/\\n/g' "$f"; n="$(basename "$f" | tr '[:upper:]' '[:lower:]')"; [ "$(basename "$f")" = "$n" ] || mv "$f" "$(dirname "$f")/$n"; done
artifacts:
paths:
- coreSubProjects/core/src/main/resources/assets/distanthorizons/lang/**
expire_in: 1 day
when: always
@@ -0,0 +1,27 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [cleanroom:runClient]" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="cleanroom:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<ExternalSystemDebugDisabled>false</ExternalSystemDebugDisabled>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<GradleProfilingDisabled>false</GradleProfilingDisabled>
<GradleCoverageDisabled>false</GradleCoverageDisabled>
<method v="2" />
</configuration>
</component>
-12
View File
@@ -1,12 +0,0 @@
FROM eclipse-temurin:25-jdk
WORKDIR /home/build/
COPY ./gradlew .
RUN chmod +x ./gradlew
CMD echo "\r========== [CLEAN: $MC_VER] ==========" && \
./gradlew clean -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
echo "\r========== [BUILD: $MC_VER] ==========" && \
./gradlew build -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
echo "\r========== [MERGE: $MC_VER] ==========" && \
./gradlew mergeJars -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
echo "\r========== [DONE: $MC_VER] =========="
+33 -126
View File
@@ -12,91 +12,18 @@ Below is a video demonstrating the system:
<a href="https://youtu.be/SxQdbtjGEsc" target="_blank">![Distant Horizons - Alpha 2.0](https://i.ytimg.com/vi/SxQdbtjGEsc/hqdefault.jpg)</a>
<br>
## Minecraft and Library Versions
### This branch supports the following versions of Minecraft:
#### 1.20.4, 1.20.3 (Default)
Fabric: 0.15.1\
Fabric API: 0.91.2+1.20.4\
Forge: 49.0.30\
NeoForge: 118-beta\
Parchment: 1.20.2:2023.12.10\
Modmenu: 9.0.0-pre.1
#### 1.20.2
Fabric: 0.14.24\
Fabric API: 0.90.4+1.20.2\
Forge: 48.0.13\
Parchment: 1.20.1:2023.09.03\
Modmenu: 8.0.0
#### 1.20.1, 1.20
Fabric: 0.14.24\
Fabric API: 0.90.4+1.20.1\
Forge: 47.2.1\
Parchment: 1.20.1:2023.09.03\
Modmenu: 7.2.2
#### 1.19.4
Fabric: 0.14.24\
Fabric API: 0.87.1+1.19.4\
Forge: 45.2.4\
Parchment: 1.19.4:2023.06.26\
Modmenu: 6.3.1
#### 1.19.2
Fabric: 0.14.24\
Fabric API: 0.76.1+1.19.2\
Forge: 43.3.2\
Parchment: 1.19.2:2022.11.27\
Modmenu: 4.2.0-beta.2
#### 1.18.2
Fabric: 0.14.24\
Fabric API: 0.76.0+1.18.2\
Forge: 40.2.10\
Parchment: 1.18.2:2022.11.06\
Modmenu: 3.2.5
#### 1.17.1, 1.17
Fabric: 0.14.24\
Fabric API: 0.46.1+1.17\
Forge: 37.1.1\
Parchment: 1.17.1:2021.12.12\
Modmenu: 2.0.14
#### 1.16.5, 1.16.4
Fabric: 0.14.24\
Fabric API: 0.42.0+1.16\
Forge: 36.2.39\
Parchment: 1.16.5:2022.03.06\
Modmenu: 1.16.22
### Versions no longer supported
- 1.18.1, 1.18
- 1.19.1, 1.19
- 1.19.3
<br>
### Plugin and Library versions
Gradle: 8.5\
Fabric loom: 1.4-SNAPSHOT\
Architectury loom (Forge gradle replacement): 1.4-SNAPSHOT\
Sponge vanilla gradle: 0.2.1-SNAPSHOT\
Java Preprocessor plugin: Manifold Preprocessor
## Translations
[![Crowdin](https://badges.crowdin.net/distant-horizons/localized.svg)](https://crowdin.com/project/distant-horizons)\
Crowdin Project: [Distant Horizons](https://crowdin.com/project/distant-horizons)\
Guidelines: [translations.md](translations.md)
<br>
## Source Code Installation
### Prerequisites
* A Java Development Kit (JDK) for Java 17 (recommended) or newer. <br>
* A Java Development Kit (JDK) for Java 25 (recommended) or newer. <br>
Visit https://www.oracle.com/java/technologies/downloads/ for installers.
* Git or someway to clone git projects. <br>
Visit https://git-scm.com/ for installers.
@@ -104,15 +31,10 @@ Java Preprocessor plugin: Manifold Preprocessor
**If using IntelliJ:**
1. Install the Manifold plugin
- https://plugins.jetbrains.com/plugin/10057-manifold-ij
2. Open IDEA and import the build.gradle
3. Refresh the Gradle project in IDEA if required
**If using Eclipse: (Note that Eclipse doesn't support Manifold's preprocessor!)**
1. Run the command: `./gradlew geneclipseruns`
2. Run the command: `./gradlew eclipse`
3. Make sure eclipse has the JDK 17 installed. (This is needed so that eclipse can run minecraft)
4. Import the project into eclipse
<br>
## Switching Versions
@@ -127,72 +49,42 @@ In IntelliJ, you will also need to do a gradle sync if it didn't happen automati
## Compiling
Prerequisites:
- JDK 17 or newer
From the File Explorer:
1. Download and extract the project zip
2. Download the core from https://gitlab.com/distant-horizons-team/distant-horizons-core and extract into a folder called `coreSubProjects`
3. Open a terminal emulator in the project folder (On Windows you can type `cmd` in the title bar)
4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows)
5. Merge the jars with `./gradlew mergeJars`
6. The compiled jar file will be in the folder `Merged`
- JDK 25 or newer
From the command line:
1. `git clone --recurse-submodules https://gitlab.com/distant-horizons-team/distant-horizons.git`
2. `cd distant-horizons`
3. `./gradlew assemble`
4. `./gradlew mergeJars`
5. The compiled jar file will be in the folder `Merged`
5. The compiled jar file will be in the folder `\build\libs`
Run tests with: `./gradlew test`
From the File Explorer:
1. Download and extract the project zip
2. Download the core from https://gitlab.com/distant-horizons-team/distant-horizons-core and extract into a folder called `coreSubProjects`
3. Open command prompt/terminal in the project folder
4. Run the commands: `./gradlew assemble`
6. The compiled jar file will be in the folder `\build\libs`
>Note: You can add the argument `-PmcVer=?` to tell gradle to build a selected MC version instead of having to modify the `gradle.properties` file.\
> For example: `./gradlew assemble -PmcVer=1.18.2`
<br>
## Compiling with Docker
`./compile <version>`
You can also locally compile the DH jars without a Java environment by using Docker. Where `<version>` is the version of Minecraft to compile for (ie `1.20.1`), or the keyword `all`. See [Versions](#minecraft-and-library-versions) for a list of all supported values.
<br>
## Other commands
`./gradlew --refresh-dependencies` to refresh local dependencies.
`./gradlew clean` to delete any compiled code.
<br>
## Note to self
The Minecraft source code is NOT added to your workspace in an editable way. Minecraft is treated like a normal Library. Sources are there for documentation and research purposes only.
Source code uses Mojang mappings & [Parchment](https://parchmentmc.org/) mappings.
To generate the source code run `./gradlew genSources` <br>
If your IDE fails to auto-detect the source jars when browsing Minecraft classes; manually select the JAR file ending with -sources.jar when prompted by your IDE. <br>
(In IntelliJ it's at the top where it says "choose sources" when browsing a Minecraft class)
<br>
## Other Useful commands
Run the standalone jar: `./gradlew run` <br>
Build the standalone jar: `./gradlew core:build` <br>
Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build` <br>
Only build Forge: `./gradlew forge:assemble` or `./gradlew forge:build` <br>
Run the Fabric client (for debugging): `./gradlew fabric:runClient` <br>
Run the Forge client (for debugging): `./gradlew forge:runClient` <br>
Delete all compiled code: `./gradlew clean` <br>
Refresh local dependencies: `./gradlew --refresh-dependencies`
To build all versions: `./buildAll` (all builds will end up in the `Merged` folder)
To build all versions: `./buildAll`
<br>
## Open Source Acknowledgements
## Open Source Libraries
Forgix (To merge multiple mod versions into one jar) [_Formerly_ [_DHJarMerger_](https://github.com/Ran-helo/DHJarMerger)]\
https://github.com/PacifistMC/Forgix
@@ -208,3 +100,18 @@ https://github.com/blackears/svgSalamander
sqlite-jdbc\
https://github.com/xerial/sqlite-jdbc
## Acknowledgements
Distant Horizons has been graciously provided an open source license for <a href="https://www.yourkit.com/java/profiler/">YourKit Java Profiler</a>.
> <img src="https://www.yourkit.com/images/yklogo.png">
>
> YourKit supports open source projects with innovative and intelligent tools
for monitoring and profiling Java and .NET applications.
YourKit is the creator of <a href="https://www.yourkit.com/java/profiler/">YourKit Java Profiler</a>,
<a href="https://www.yourkit.com/dotnet-profiler/">YourKit .NET Profiler</a>,
and <a href="https://www.yourkit.com/youmonitor/">YourKit YouMonitor</a>.
+7 -1
View File
@@ -4,10 +4,10 @@ plugins {
}
forgix {
autoRun = true
// add the mod loaders to the end of the jar
// put together in the format: "a", "a-b", "a-b-c"
int loaderCount = 0;
String modLoaders = "";
((String) gradle.builds_for)
.split(",")
@@ -20,7 +20,13 @@ forgix {
}
modLoaders += loaderName;
loaderCount++;
}
// run if there are multiple launchers that need merging
autoRun = (loaderCount > 1);
// merged jars are named in the format:
// "DistantHorizons-3.0.1-b-dev-26.1-fabric-neoforge.jar"
archiveClassifier = modLoaders
+35
View File
@@ -0,0 +1,35 @@
@echo off & setlocal enabledelayedexpansion
echo ==================== Getting versions to build... ====================
mkdir _buildAllJars 2>nul
del _buildAllJars\* /Q 2>nul
set "ROOT=%~dp0"
set "WORK_DIR=%ROOT%_buildWorkers"
mkdir "%WORK_DIR%" 2>nul
REM get the number of versions to compile
set count=0
for %%f in (versionProperties\*) do set /a count+=1
echo ==================== Found %count% versions to build in parallel ====================
REM Launch a parallel job for each version
for %%f in (%ROOT%versionProperties\*) do (
set version=%%~nf
echo starting [!version!]...
start "Build !version!" cmd /c ""%ROOT%build_worker.bat" "!version!" "%ROOT%" "%WORK_DIR%" ""..\..\_buildAllJars"""
REM Minor timeout between launches so we can stop the build early if we only want
REM to test part of the script and to reduce startup load
timeout /t 3 /nobreak
REM 2>nul to supress a harmless warning that the for loop
REM "cannot find the drive specified"
) 2>nul
echo ==================== All builds started... Completed Jars will be in _buildAllJars ====================
endlocal
+127 -19
View File
@@ -6,6 +6,7 @@ import org.apache.tools.zip.ZipOutputStream
import javax.annotation.Nonnull
import java.util.function.Function
import java.util.function.Predicate
import groovy.json.JsonSlurper
// Convention plugin for all MC-facing subprojects (common + loaders).
// Common uses this directly; loaders use it via unimined-fabric/forge/neoforge.
@@ -23,6 +24,9 @@ plugins {
def isNotCommonProject = project.name != "common"
if (isNotCommonProject) {
evaluationDependsOn(":common")
}
// ==================== Version Properties ====================
@@ -54,7 +58,12 @@ repositories {
url "https://www.cursemaven.com"
content { includeGroup "curse.maven" }
}
maven { url "https://repo.spongepowered.org/maven/" }
maven {
url "https://repo.spongepowered.org/maven/"
// exclusion is needed since sponge has a deprecated version of fabric
// that gradle would prefer to get over the up-to-date version modrinth provides
content { excludeGroupByRegex "net\\.fabricmc(\\..*)?" }
}
maven { url "https://maven.terraformersmc.com/" }
maven { url "https://maven.neoforged.net/releases/" }
flatDir {
@@ -116,6 +125,15 @@ if (isNotCommonProject) {
'Multi-Release': true,
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain',
)
if (project.name == "cleanroom") {
attributes(
'ModType': 'CRL',
'MixinConfigs': "${mod_id}.default.mixin.json,${mod_id}.mod.mixin.json",
'FMLCorePlugin': 'com.seibel.distanthorizons.cleanroom.DistantHorizonsLoadingPlugin',
'FMLCorePluginContainsFMLMod': true,
'FMLAT': "${gradle.ext.accessWidenerVersion}.distanthorizons_at.cfg"
)
}
}
}
}
@@ -128,8 +146,14 @@ unimined.minecraft(sourceSets.main, true) {
if (gradle.ext.minecraft_version.startsWith("1.")) { // 26.1+ doesn't use obfuscation
mappings {
mojmap()
devNamespace "mojmap"
if(gradle.ext.minecraft_version.startsWith("1.12.2")){
mcp("stable", "39-1.12")
}
else{
mojmap()
devNamespace "mojmap"
}
}
}
}
@@ -160,18 +184,23 @@ if (isNotCommonProject) {
source(project(":common").sourceSets.main.allSource)
}
} else {
// Common: fabric for compilation + access widener, no jar remapping or runs
unimined.minecraft {
fabric {
loader gradle.ext.fabric_loader_version
accessWidener project.file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
if (gradle.ext.minecraft_version.equals("1.12.2")) {
cleanroom {
loader gradle.ext.cleanroom_loader_version
accessTransformer project.file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons_at.cfg")
}
} else {
fabric {
loader gradle.ext.fabric_loader_version
accessWidener project.file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
}
}
defaultRemapJar = false
runs.off = true
}
}
// ==================== Configurations ====================
evaluationDependsOn(":core")
@@ -341,12 +370,25 @@ if (isNotCommonProject) {
def loaderPaths = configurations.minecraftLibraries.resolve().collect { it.path }.toSet()
tasks.withType(JavaExec).configureEach { runTask ->
dependsOn(shadowJar)
classpath = files(shadowJar.archiveFile) + classpath.filter { file ->
!file.path.contains(project.buildDir.path) &&
!file.path.contains("core${File.separator}build") &&
!file.path.contains("api${File.separator}build") &&
!file.path.contains("common${File.separator}build") &&
!(shadowedPaths.contains(file.path) && !loaderPaths.contains(file.path))
if (project.name != "cleanroom") {
classpath = files(shadowJar.archiveFile) + classpath.filter { file ->
file != shadowJar.archiveFile.get().asFile &&
!file.path.contains(project.buildDir.path) &&
!file.path.contains("core${File.separator}build") &&
!file.path.contains("api${File.separator}build") &&
!file.path.contains("common${File.separator}build") &&
!(shadowedPaths.contains(file.path) && !loaderPaths.contains(file.path))
}
} else {
// For cleanroom, don't put shadow jar on app classpath.
// crl.dev.extrapath loads it via LaunchClassLoader instead.
classpath = classpath.filter { file ->
!file.path.contains(project.buildDir.path) &&
!file.path.contains("core${File.separator}build") &&
!file.path.contains("api${File.separator}build") &&
!file.path.contains("common${File.separator}build") &&
!(shadowedPaths.contains(file.path) && !loaderPaths.contains(file.path))
}
}
// Shared run directory so all loaders use the same worlds
@@ -361,6 +403,31 @@ if (isNotCommonProject) {
!arg.startsWith("-XX:MaxGCPauseMillis")
}
runTask.jvmArgs = filteredArgs
if(project.name == "forge"
|| project.name == "neoforge"
|| project.name == "cleanroom")
{
// fix (Neo)forge, Cleanroom debug running
doFirst {
def modsDir = rootProject.file("run/${isClient ? 'client' : 'server'}/mods")
modsDir.mkdirs()
// Remove any stale DH jars before copying the fresh one
modsDir.listFiles()?.each({ file ->
if (file.name.startsWith(rootProject.mod_name))
{
file.delete()
}
});
// Copy shadow jar into mods folder so (Neo)Forge discovers it properly
copy {
from shadowJar.archiveFile
into modsDir
}
}
}
// JVM args
runTask.jvmArgs(
@@ -371,7 +438,8 @@ if (isNotCommonProject) {
//"-XX:+ZGenerational",
rootProject.minecraftMemoryJavaArg,
)
if (isClient) {
if (isClient)
{
runTask.jvmArgs(
"-Dminecraft.api.auth.host=https://nope.invalid",
"-Dminecraft.api.account.host=https://nope.invalid",
@@ -382,11 +450,23 @@ if (isNotCommonProject) {
// 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",
"--renderDebugLabels"
)
// enabling tracy causes constant memory growth so it isn't always desired
if (rootProject.minecraftEnableTracy == "true")
{
// "--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")
runTask.args("--tracy")
}
}
}
tasks.downgradeJar.inputFile.set(tasks.named("remapJar").flatMap { it.archiveFile })
tasks.jar.finalizedBy(tasks.named("remapJar"))
tasks.named("remapJar").configure { finalizedBy(tasks.shadeDowngradedApi) }
}
}
@@ -398,16 +478,22 @@ if (isNotCommonProject) {
def resourceTargets = [
"build_info.json",
"fabric.mod.json",
"mcmod.info",
"quilt.mod.json",
"META-INF/mods.toml",
"META-INF/neoforge.mods.toml",
]
def compatible_forgemc_versions = "${rootProject.compatible_minecraft_versions}".replaceAll("\"", "").replaceAll("]", ",)")
// incoming format: `["26.2.0","26.2-alpha.9"]`
// outgoing format: `[26.2.0],[26.2-alpha.9]`
def compatible_forgemc_versions = "${rootProject.compatible_minecraft_versions}"
.replaceAll("\",\"", "],[")
.replaceAll("\"", "")
// Quilt contributors
def quilt_contributors = []
def mod_author_list = rootProject.mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",")
def cleanroom_author_list = rootProject.mod_authors.replace('[', '').replace(']', '').split(',').collect({ it.trim().replace('"', '') }).join('", "')
for (dev in mod_author_list) {
quilt_contributors.push("\"${dev.strip()}\": \"Developer\"")
}
@@ -425,9 +511,11 @@ if (isNotCommonProject) {
def replaceProperties = [
version : rootProject.mod_version,
mod_id : rootProject.mod_id,
mod_name : rootProject.mod_readable_name,
group : rootProject.maven_group,
authors : rootProject.mod_authors,
cleanroom_authors : cleanroom_author_list,
description : rootProject.mod_description,
homepage : rootProject.mod_homepage,
source : rootProject.mod_source,
@@ -445,6 +533,7 @@ if (isNotCommonProject) {
fabric_incompatibility_list : rootProject.fabric_incompatibility_list,
fabric_recommend_list : rootProject.fabric_recommend_list,
neoforge_version_range : rootProject.neoforge_version_range,
logo_path : "assets/distanthorizons/icon.png"
]
inputs.properties replaceProperties
@@ -455,7 +544,7 @@ if (isNotCommonProject) {
// Remove unused access wideners
exclude { file ->
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener") {
if ((file.name.contains(".distanthorizons.accesswidener") && file.name != "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener")) {
return true
}
return false
@@ -475,6 +564,25 @@ if (isNotCommonProject) {
from fileTree(project(":core").file("src/main/resources"))
into project.file("build/resources/main")
}
tasks.register("convertJsonToLang") {
dependsOn(copyCoreResources)
File input = project.file("build/resources/main/assets/distanthorizons/lang/en_us.json")
File output = project.file("build/resources/main/assets/distanthorizons/lang/en_us.lang")
inputs.file(input)
outputs.file(output)
doLast {
output.withWriter("UTF-8") { writer ->
writer.writeLine("#PARSE_ESCAPES")
new JsonSlurper()
.parse(input)
.each { key, value ->
writer.writeLine("${key}=${value.toString().replace("%", "%%").replace("\n", "\\n")}")
}
}
}
}
// ==================== JVMDowngrader ====================
@@ -0,0 +1,15 @@
plugins {
id 'dh-loader'
}
unimined.minecraft {
cleanroom {
loader gradle.ext.cleanroom_loader_version
useToolchains = false
accessTransformer project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons_at.cfg")
runs.all {
systemProperty("crl.dev.mixin", "${mod_id}.default.mixin.json,${mod_id}.mod.mixin.json")
systemProperty("fml.coreMods.load", "com.seibel.distanthorizons.cleanroom.DistantHorizonsLoadingPlugin")
}
}
}
+41
View File
@@ -0,0 +1,41 @@
@echo off & setlocal enabledelayedexpansion
set "VERSION=%~1"
set "ROOT=%~2"
set "WORK_DIR=%~3"
set "WORKER=%WORK_DIR%\%VERSION%"
set "JAR_OUTPUT_DIR=%~4"
REM remove the ending "\" from the root folder, otherwise the final quote
REM in the robocopy command will be escaped and it won't run
if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%"
set "WORKER=%~3\%~1"
set "BUILT_JAR_DIR=%WORKER%\build\forgix"
echo ==================== [%VERSION%] Copying workspace ====================
mkdir "%WORKER%"
robocopy "%ROOT%" "%WORKER%" /E /XD "%WORKER%" "_buildWorkers" "buildAllJars" ".gradle" "build" ".git" ".idea" ".gitlab" "run" "testScripts" /NFL /NDL
echo ==================== [%VERSION%] Cleaning ====================
cd /d "%WORKER%"
call .\gradlew.bat clean
REM optional arg that can be added if we want to log the result to a file
REM >"%WORK_DIR%\build_%VERSION%.log" 2>&1
echo ==================== [%VERSION%] Assembling ====================
call .\gradlew.bat assemble -PmcVer="%VERSION%"
REM optional arg that can be added if we want to log the result to a file
REM >>"%WORK_DIR%\build_%VERSION%.log" 2>&1
echo ==================== [%VERSION%] Exporting ====================
mkdir "%JAR_OUTPUT_DIR%"
robocopy "%BUILT_JAR_DIR%" "%JAR_OUTPUT_DIR%" /NFL /NDL
echo ==================== [%VERSION%] Done ====================
endlocal
REM can be uncommented for debugging
REM pause
+48
View File
@@ -0,0 +1,48 @@
plugins {
id 'unimined-cleanroom'
}
// ==================== Mod Dependency Helper ====================
def addMod(path, enabled) {
if (enabled == "2")
dependencies { modImplementation(path) }
else if (enabled == "1")
dependencies { compileOnly(path) }
}
// ==================== Dependencies ====================
dependencies {
}
// ==================== Tasks ====================
task deleteResources(type: Delete) {
delete file("build/resources/main")
}
processResources {
rename '(.+_at.cfg)', 'META-INF/$1'
dependsOn(copyCoreResources)
dependsOn(convertJsonToLang)
// dependsOn(copyCommonLoaderResources)
}
tasks.named('runClient') {
dependsOn(copyCoreResources)
// dependsOn(copyCommonLoaderResources)
finalizedBy(deleteResources)
}
sourcesJar {
def commonSources = project(":common").sourcesJar
dependsOn commonSources
from commonSources.archiveFile.map { zipTree(it) }
}
@@ -0,0 +1,251 @@
/*
* 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.cleanroom;
import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.util.ProxyUtil;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.world.ChunkEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.InputEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL32;
import java.util.concurrent.AbstractExecutorService;
public class CleanroomClientProxy implements AbstractModInitializer.IEventProxy
{
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final CleanroomPluginPacketSender PACKET_SENDER = (CleanroomPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static World GetEventLevel(WorldEvent e) { return e.getWorld(); }
@Override
public void registerEvents()
{
MinecraftForge.EVENT_BUS.register(this);
MinecraftForge.EVENT_BUS.register(FMLCommonHandler.instance());
CleanroomPluginPacketSender.setPacketHandler(ClientApi.INSTANCE::pluginMessageReceived);
}
//==============//
// world events //
//==============//
@SubscribeEvent
public void clientLevelLoadEvent(WorldEvent.Load event)
{
LOGGER.info("level load");
World level = event.getWorld();
if (!(level instanceof WorldClient clientLevel))
{
return;
}
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel, true);
ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper);
}
@SubscribeEvent
public void clientLevelUnloadEvent(WorldEvent.Unload event)
{
LOGGER.info("level unload");
World level = event.getWorld();
if (!(level instanceof WorldClient clientLevel))
{
return;
}
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel);
ClientApi.INSTANCE.clientLevelUnloadEvent(clientLevelWrapper);
}
//==============//
// chunk events //
//==============//
//region
@SubscribeEvent
public void rightClickBlockEvent(PlayerInteractEvent.RightClickBlock event)
{
if (MC.clientConnectedToDedicatedServer())
{
World level = event.getWorld();
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(level);
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(wrappedLevel, event.getPos().getX(), event.getPos().getZ()))
{
return;
}
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
executor.execute(() ->
{
Chunk chunk = level.getChunk(event.getPos());
SharedApi.INSTANCE.applyChunkUpdate(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel);
});
}
}
}
@SubscribeEvent
public void leftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event)
{
if (MC.clientConnectedToDedicatedServer())
{
World level = event.getWorld();
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(level);
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(wrappedLevel, event.getPos().getX(), event.getPos().getZ()))
{
return;
}
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
executor.execute(() ->
{
Chunk chunk = level.getChunk(event.getPos());
SharedApi.INSTANCE.applyChunkUpdate(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel);
});
}
}
}
@SubscribeEvent
public void clientChunkLoadEvent(ChunkEvent.Load event)
{
if (MC.clientConnectedToDedicatedServer())
{
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
IChunkWrapper chunkWrapper = new ChunkWrapper(event.getChunk(), wrappedLevel);
SharedApi.INSTANCE.applyChunkUpdate(chunkWrapper, wrappedLevel);
}
}
//endregion
//==============//
// key bindings //
//==============//
//region
@SubscribeEvent
public void registerKeyBindings(InputEvent.KeyInputEvent event)
{
/* if (Minecraft.getMinecraft().player == null)
{
return;
}
if (event.getAction() != GLFW.GLFW_PRESS)
{
return;
}
ClientApi.INSTANCE.keyPressedEvent(event.getKey());*/
}
//endregion
//===========//
// rendering //
//===========//
//region
@SubscribeEvent
public void afterLevelRenderEvent(TickEvent.RenderTickEvent event)
{
if (event.type.equals(TickEvent.RenderTickEvent.Type.RENDER))
{
try
{
// should generally only need to be set once per game session
// allows DH to render directly to Optifine's level frame buffer,
// allowing better shader support
MinecraftRenderWrapper.INSTANCE.finalLevelFrameBufferId = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING);
}
catch (Exception | Error e)
{
LOGGER.error("Unexpected error in afterLevelRenderEvent: "+e.getMessage(), e);
}
}
}
@SubscribeEvent
public void onRenderOverlay(RenderGameOverlayEvent.Text event)
{
Minecraft mc = Minecraft.getMinecraft();
if (event.isCanceled()
|| !mc.gameSettings.showDebugInfo)
{
return;
}
F3Screen.addStringToDisplay(event.getRight());
}
//endregion
}
@@ -0,0 +1,147 @@
/*
* 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.cleanroom;
import com.seibel.distanthorizons.cleanroom.modAccessor.ModChecker;
import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.commands.CommandInitializer;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.InternalServerGenerator;
import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeChunkManager;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.*;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;
import java.util.List;
import java.util.function.Consumer;
/**
* Initialize and setup the Mod. <br>
* If you are looking for the real start of the mod
* check out the ClientProxy.
*/
@Mod(modid = ModInfo.ID, name = ModInfo.NAME, version = ModInfo.VERSION)
public class CleanroomMain extends AbstractModInitializer
{
@Mod.Instance
public static CleanroomMain instance;
@Mod.EventHandler
public void preinit(FMLPreInitializationEvent event)
{
Configurator.setLevel("org.sqlite", Level.INFO);
ForgeChunkManager.setForcedChunkLoadingCallback(CleanroomMain.instance, (tickets, world) -> { });
}
@Mod.EventHandler
public void init(FMLInitializationEvent event)
{
if (FMLCommonHandler.instance().getEffectiveSide().isClient())
{
this.onInitializeClient();
}
else
{
this.onInitializeServer();
}
}
@Override
protected void createInitialSharedBindings()
{
SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new CleanroomPluginPacketSender());
}
@Override
protected void createInitialClientBindings() { /* no additional setup needed currently */ }
@Override
protected IEventProxy createClientProxy() { return new CleanroomClientProxy(); }
@Override
protected IEventProxy createServerProxy(boolean isDedicated) { return new CleanroomServerProxy(isDedicated); }
@Override
protected void initializeModCompat()
{
}
/* @Override
protected void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler)
{ MinecraftForge.EVENT_BUS.addListener((RegisterCommandsEvent e) -> { eventHandler.accept(e.getDispatcher()); }); }*/
@Override
protected void subscribeClientStartedEvent(Runnable eventHandler)
{
// Just run the event handler, since there are no proper ClientLifecycleEvent for the client
// to signify readiness other than FmlClientSetupEvent
eventHandler.run();
}
@Mod.EventHandler
public void onServerStarting(FMLServerStartingEvent event)
{
event.registerServerCommand(CommandInitializer.initCommands());
}
@Mod.EventHandler
public void onServerAboutToStart(FMLServerAboutToStartEvent event)
{
if (eventHandlerStartServer != null)
{
eventHandlerStartServer.accept(event.getServer());
}
}
Consumer<MinecraftServer> eventHandlerStartServer;
@Override
protected void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler)
{
eventHandlerStartServer = eventHandler;
}
@Override
protected void runDelayedSetup() { SingletonInjector.INSTANCE.runDelayedSetup(); }
// ServerWorldLoadEvent
@Mod.EventHandler
public void dedicatedWorldLoadEvent(FMLServerAboutToStartEvent event)
{
ServerApi.INSTANCE.serverLoadEvent(event.getServer().isDedicatedServer());
}
// ServerWorldUnloadEvent
@Mod.EventHandler
public void serverWorldUnloadEvent(FMLServerStoppingEvent event)
{
ServerApi.INSTANCE.serverUnloadEvent();
}
}
@@ -0,0 +1,136 @@
/*
* 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.cleanroom;
import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.fml.relauncher.Side;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class CleanroomPluginPacketSender extends AbstractPluginPacketSender
{
public static final SimpleNetworkWrapper PLUGIN_CHANNEL =
NetworkRegistry.INSTANCE.newSimpleChannel(
AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE
);
public static void setPacketHandler(Consumer<AbstractNetworkMessage> consumer)
{ setPacketHandler((player, message) -> consumer.accept(message)); }
static BiConsumer<IServerPlayerWrapper, AbstractNetworkMessage> consumerPacket;
public static void setPacketHandler(BiConsumer<IServerPlayerWrapper, AbstractNetworkMessage> consumer)
{
PLUGIN_CHANNEL.registerMessage(MessageWrapper.Handler.class, MessageWrapper.class, 0, Side.CLIENT);
PLUGIN_CHANNEL.registerMessage(MessageWrapper.Handler.class, MessageWrapper.class, 0, Side.SERVER);
consumerPacket = consumer;
}
@Override
public void sendToServer(AbstractNetworkMessage message)
{ PLUGIN_CHANNEL.sendToServer(new MessageWrapper(message)); }
@Override
public void sendToClient(EntityPlayerMP serverPlayer, AbstractNetworkMessage message)
{ PLUGIN_CHANNEL.sendTo(new MessageWrapper(message), serverPlayer); }
//================//
// helper classes //
//================//
//region
// Forge doesn't support using abstract classes
@SuppressWarnings({"ClassCanBeRecord", "RedundantSuppression"})
public static class MessageWrapper implements IMessage
{
public AbstractNetworkMessage message;
//=============//
// constructor //
//=============//
//region
public MessageWrapper(AbstractNetworkMessage message) { this.message = message; }
public MessageWrapper()
{
// For reflection
}
//endregion
@Override
public void fromBytes(ByteBuf buf)
{
int messageId = buf.readByte();
message = MessageRegistry.INSTANCE.createMessage(messageId);
message.decode(buf);
}
@Override
public void toBytes(ByteBuf buf)
{
buf.writeByte(MessageRegistry.INSTANCE.getMessageId(message));
message.encode(buf);
}
public static class Handler implements IMessageHandler<MessageWrapper, IMessage>
{
@Override
public IMessage onMessage(MessageWrapper wrapper, MessageContext context)
{
if (wrapper.message != null)
{
if (context.side == Side.SERVER)
{
consumerPacket.accept(ServerPlayerWrapper.getWrapper(context.getServerHandler().player), wrapper.message);
}
else
{
consumerPacket.accept(null, wrapper.message);
}
}
return null; // No response needed
}
}
}
//endregion
}
@@ -0,0 +1,181 @@
/*
* 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.cleanroom;
import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.commands.CommandInitializer;
import com.seibel.distanthorizons.common.commonMixins.MixinChunkMapCommon;
import com.seibel.distanthorizons.common.util.ProxyUtil;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.InternalServerGenerator;
import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.ForgeChunkManager;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.ChunkDataEvent;
import net.minecraftforge.event.world.ChunkEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLServerAboutToStartEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.event.FMLServerStoppingEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import java.lang.reflect.Field;
import static com.seibel.distanthorizons.cleanroom.CleanroomMain.instance;
public class CleanroomServerProxy implements AbstractModInitializer.IEventProxy
{
private static final CleanroomPluginPacketSender PACKET_SENDER = (CleanroomPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
private static World GetEventLevel(WorldEvent e) { return e.getWorld(); }
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private final ServerApi serverApi = ServerApi.INSTANCE;
private final boolean isDedicated;
@Override
public void registerEvents()
{
MinecraftForge.EVENT_BUS.register(this);
FMLCommonHandler.instance().bus().register(this);
if (this.isDedicated)
{
PACKET_SENDER.setPacketHandler(ServerApi.INSTANCE::pluginMessageReceived);
}
}
//=============//
// constructor //
//=============//
//region
public CleanroomServerProxy(boolean isDedicated) { this.isDedicated = isDedicated; }
//endregion
//========//
// events //
//========//
//region
// ServerLevelLoadEvent
@SubscribeEvent
public void serverLevelLoadEvent(WorldEvent.Load event)
{
if (GetEventLevel(event) instanceof WorldServer)
{
this.serverApi.serverLevelLoadEvent(getServerLevelWrapper((WorldServer) GetEventLevel(event)));
}
}
// ServerLevelUnloadEvent
@SubscribeEvent
public void serverLevelUnloadEvent(WorldEvent.Unload event)
{
if (GetEventLevel(event) instanceof WorldServer)
{
this.serverApi.serverLevelUnloadEvent(getServerLevelWrapper((WorldServer) GetEventLevel(event)));
}
}
@SubscribeEvent
public void serverChunkLoadEvent(ChunkEvent.Load event)
{
ILevelWrapper levelWrapper = ProxyUtil.getLevelWrapper(GetEventLevel(event));
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), levelWrapper);
this.serverApi.serverChunkLoadEvent(chunk, levelWrapper);
}
@SubscribeEvent
public void serverChunkSaveEvent(ChunkDataEvent.Save event)
{
if (event.getWorld() instanceof WorldServer worldServer)
{
MixinChunkMapCommon.onChunkSave(worldServer, event.getChunk());
}
}
@SubscribeEvent
public void playerLoggedInEvent(PlayerEvent.PlayerLoggedInEvent event)
{ this.serverApi.serverPlayerJoinEvent(getServerPlayerWrapper(event)); }
@SubscribeEvent
public void playerLoggedOutEvent(PlayerEvent.PlayerLoggedOutEvent event)
{ this.serverApi.serverPlayerDisconnectEvent(getServerPlayerWrapper(event)); }
@SubscribeEvent
public void playerChangedDimensionEvent(PlayerEvent.PlayerChangedDimensionEvent event)
{
this.serverApi.serverPlayerLevelChangeEvent(
getServerPlayerWrapper(event),
getServerLevelWrapper(event.fromDim, event),
getServerLevelWrapper(event.toDim, event)
);
}
//endregion
//================//
// helper methods //
//================//
//region
private static ServerLevelWrapper getServerLevelWrapper(WorldServer level) { return ServerLevelWrapper.getWrapper(level); }
private static ServerLevelWrapper getServerLevelWrapper(int dimensionId, PlayerEvent event)
{
MinecraftServer server = event.player.getServer();
if (server == null)
{
LOGGER.error("getServerLevelWrapper: server is null for player {}", event.player.getName());
return null;
}
return getServerLevelWrapper(server.getWorld(dimensionId));
}
private static ServerPlayerWrapper getServerPlayerWrapper(PlayerEvent event)
{ return ServerPlayerWrapper.getWrapper((EntityPlayerMP) event.player); }
//endregion
}
@@ -0,0 +1,56 @@
/*
* 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.cleanroom;
import net.minecraftforge.fml.common.Loader;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import java.util.List;
import java.util.Set;
public class DistantHorizonsConfigPlugin implements IMixinConfigPlugin
{
private static final Logger LOGGER = LogManager.getLogger();
@Override
public void onLoad(String mixinPackage)
{ }
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName)
{
/* return switch (mixinClassName.split("\\.")[5]) {
case "mist" -> Loader.isModLoaded("mist");
default -> true;
};*/
return true;
}
@Override public String getRefMapperConfig() { return null; }
@Override public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) { }
@Override public List<String> getMixins() { return null; }
@Override public void preApply(String targetClassName, ClassNode classNode, String mixinClassName, IMixinInfo mixinInfo) { }
@Override public void postApply(String targetClassName, ClassNode classNode, String mixinClassName, IMixinInfo mixinInfo) { }
}
@@ -0,0 +1,52 @@
/*
* 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.cleanroom;
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
public class DistantHorizonsLoadingPlugin implements IFMLLoadingPlugin
{
@Override
public @Nullable String[] getASMTransformerClass()
{
return new String[0];
}
@Override
public @Nullable String getModContainerClass()
{
return null;
}
@Override
public @Nullable String getSetupClass()
{
return null;
}
@Override
public void injectData(Map<String, Object> data) { }
@Override
public @Nullable String getAccessTransformerClass()
{
return null;
}
}
@@ -0,0 +1,84 @@
/*
* 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.cleanroom.mixins.client;
import com.seibel.distanthorizons.common.commonMixins.MixinVanillaFogCommon;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.init.MobEffects;
import org.apache.logging.log4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(EntityRenderer.class)
public class MixinEntityRenderer
{
@Shadow
@Final
private DynamicTexture lightmapTexture;
@Shadow @Final private Minecraft mc;
@Shadow @Final private static Logger LOGGER;
private static final float A_REALLY_REALLY_BIG_VALUE = 420694206942069.F;
private static final float A_EVEN_LARGER_VALUE = 42069420694206942069.F;
@Inject(at = @At("TAIL"), method = "updateLightmap")
public void onUpdateLightmap(float patrialTicks, CallbackInfo ci)
{
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
if (mc == null || mc.getWrappedClientLevel() == null)
{
return;
}
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
MinecraftRenderWrapper renderWrapper = (MinecraftRenderWrapper)SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
renderWrapper.setLightmapId(lightmapTexture.getGlTextureId(), clientLevel);
}
@Inject(at = @At("RETURN"), method = "setupFog")
private void disableSetupFog(int startCoords, float partialTicks, CallbackInfo ci)
{
boolean cancelFog = MixinVanillaFogCommon.cancelFog(startCoords, mc);
if (cancelFog)
{
GlStateManager.setFogStart(A_REALLY_REALLY_BIG_VALUE);
GlStateManager.setFogEnd(A_EVEN_LARGER_VALUE);
ClientApi.RENDER_STATE.vanillaFogEnabled = false;
}
else
{
ClientApi.RENDER_STATE.vanillaFogEnabled = true;
}
}
}
@@ -0,0 +1,46 @@
/*
* 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.cleanroom.mixins.client;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.network.play.server.SPacketJoinGame;
import net.minecraft.util.text.ITextComponent;
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(NetHandlerPlayClient.class)
public class MixinNetHandlerPlayClient
{
@Inject(method = "handleJoinGame", at = @At("RETURN"))
private void onHandleJoinGameEnd(SPacketJoinGame packet, CallbackInfo ci)
{
ClientApi.INSTANCE.onClientOnlyConnected();
}
@Inject(method = "onDisconnect", at = @At("RETURN"))
private void onDisconnect(ITextComponent reason, CallbackInfo ci)
{
ClientApi.INSTANCE.onClientOnlyDisconnected();
}
}
@@ -0,0 +1,83 @@
/*
* 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.cleanroom.mixins.client;
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiOptions;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.util.ResourceLocation;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* Adds a button to the menu to goto the config
*
* @author coolGi
* @version 12-02-2021
*/
@Mixin(GuiOptions.class)
public class MixinOptionsScreen extends GuiScreen
{
// Get the texture for the button
@Unique private static final ResourceLocation ICON_TEXTURE = new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
@Unique private static final int button_id = 99;
@Inject(at = @At("HEAD"), method = "initGui")
private void lodconfig$init(CallbackInfo ci)
{
if (Config.Client.showDhOptionsButtonInMinecraftUi.get())
this.buttonList.add(
(new TexturedButtonWidget(
button_id,
// Where the button is on the screen
this.width / 2 - 180, this.height / 6 - 12,
// Width and height of the button
20, 20,
// Offset
0, 0,
// Some textuary stuff
20, ICON_TEXTURE, 20, 40,
// Create the button and tell it where to go
// For now it goes to the client option by default
// Add a title to the button
ModInfo.ID + ".title")));
}
@Inject(at = @At("HEAD"), method = "actionPerformed", cancellable = true)
private void lodconfig$actionPerformed(GuiButton button, CallbackInfo ci)
{
if (button.id == button_id)
{
Minecraft.getMinecraft().displayGuiScreen(GetConfigScreen.getScreen(this));
ci.cancel();
}
}
}
@@ -0,0 +1,81 @@
/*
* 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.cleanroom.mixins.client;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.entity.Entity;
import net.minecraft.util.BlockRenderLayer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(RenderGlobal.class)
public class MixinRenderGlobal
{
@Shadow private WorldClient world;
@Inject(method = "renderBlockLayer(Lnet/minecraft/util/BlockRenderLayer;DILnet/minecraft/entity/Entity;)I", at = @At("HEAD"))
private void renderChunkLayer(BlockRenderLayer blockLayerIn, double partialTicks, int pass, Entity entityIn, CallbackInfoReturnable<Integer> cir)
{
if (blockLayerIn == BlockRenderLayer.SOLID)
{
float[] mcProjMatrixRaw = new float[16];
GL11.glGetFloatv(GL11.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
ClientApi.RENDER_STATE.mcProjectionMatrix = new Mat4f(mcProjMatrixRaw);
ClientApi.RENDER_STATE.mcProjectionMatrix.transpose();
float[] mcModelViewRaw = new float[16];
GL11.glGetFloatv(GL11.GL_MODELVIEW_MATRIX, mcModelViewRaw);
ClientApi.RENDER_STATE.mcModelViewMatrix = new Mat4f(mcModelViewRaw);
ClientApi.RENDER_STATE.mcModelViewMatrix.transpose();
ClientApi.RENDER_STATE.partialTickTime = (float) partialTicks;
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, this.world);
int blendSrc = GL11.glGetInteger(GL11.GL_BLEND_SRC);
int blendDst = GL11.glGetInteger(GL11.GL_BLEND_DST);
int boundTexture = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
ClientApi.INSTANCE.renderLods();
GL30.glBindVertexArray(0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
GL20.glUseProgram(0);
//Restore vanilla states
GlStateManager.depthFunc(GL11.GL_LEQUAL);
GlStateManager.bindTexture(boundTexture);
GlStateManager.tryBlendFuncSeparate(blendSrc, blendDst, GL11.GL_ONE, GL11.GL_ZERO);
}
}
}
@@ -0,0 +1,17 @@
package com.seibel.distanthorizons.cleanroom.mixins.common;
import net.minecraft.world.storage.ThreadedFileIOBase;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(ThreadedFileIOBase.class)
public class MixinThreadedFileIOBase
{
@Redirect(method = "processQueue", at = @At(value = "INVOKE", target = "Ljava/lang/Thread;sleep(J)V"))
private void reduceSleep(long millis) throws InterruptedException
{
// 0ms between chunks, 5ms when idle
Thread.sleep(millis == 25L ? 5L : 0L);
}
}
@@ -0,0 +1,66 @@
/*
* 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.cleanroom.mixins.server;
import com.seibel.distanthorizons.common.wrappers.misc.IMixinServerPlayer;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.util.ITeleporter;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
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.CallbackInfoReturnable;
@Mixin(EntityPlayerMP.class)
public abstract class MixinEntityPlayerMP implements IMixinServerPlayer
{
@Shadow
@Final
public MinecraftServer server;
@Unique
@Nullable
private volatile WorldServer distantHorizons$dimensionChangeDestination;
@Override
@Nullable
public WorldServer distantHorizons$getDimensionChangeDestination()
{ return this.distantHorizons$dimensionChangeDestination; }
@Inject(at = @At("HEAD"), method = "changeDimension(ILnet/minecraftforge/common/util/ITeleporter;)Lnet/minecraft/entity/Entity;")
public void setDimensionChangeDestination(int destinationDimensionID, ITeleporter teleporter, CallbackInfoReturnable<Entity> cir)
{ this.distantHorizons$dimensionChangeDestination = this.server.getWorld(destinationDimensionID); }
@Inject(at = @At("RETURN"), method = "clearInvulnerableDimensionChange")
public void clearDimensionChangeDestination(CallbackInfo ci)
{ this.distantHorizons$dimensionChangeDestination = null; }
}
@@ -0,0 +1,52 @@
/*
* 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.cleanroom.modAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer;
import java.io.File;
import java.util.Optional;
import java.util.stream.Stream;
public class ModChecker implements IModChecker
{
public static final ModChecker INSTANCE = new ModChecker();
@Override
public boolean isModLoaded(String modid)
{
return Loader.isModLoaded(modid);
}
@Override
public File modLocation(String modid)
{
Stream<ModContainer> foundStream = Loader.instance().getModList().stream().filter(x -> x.getModId().equals(modid));
Optional<ModContainer> container = foundStream.findFirst();
if (!container.isPresent())
{
throw new RuntimeException("Mod not found: " + modid);
}
return container.get().getSource();
}
}
@@ -0,0 +1,19 @@
{
"required": true,
"package": "com.seibel.distanthorizons.cleanroom.mixins",
"compatibilityLevel": "JAVA_8",
"target": "@env(DEFAULT)",
"mixins": [
"common.MixinThreadedFileIOBase"
],
"minVersion": "0.8.7",
"server": [
"server.MixinEntityPlayerMP"
],
"client": [
"client.MixinEntityRenderer",
"client.MixinNetHandlerPlayClient",
"client.MixinOptionsScreen",
"client.MixinRenderGlobal"
]
}
@@ -0,0 +1,11 @@
{
"required": false,
"package": "com.seibel.distanthorizons.cleanroom.mixins.mod",
"compatibilityLevel": "JAVA_8",
"target": "@env(MOD)",
"mixins": [],
"minVersion": "0.8.7",
"plugin": "com.seibel.distanthorizons.cleanroom.DistantHorizonsConfigPlugin",
"client": [
]
}
+12
View File
@@ -0,0 +1,12 @@
[{
"modid": "${mod_id}",
"name": "${mod_name}",
"version": "${version}",
"mcversion": "1.12.2",
"description": "${description}",
"authorList": ["${cleanroom_authors}"],
"credits": "",
"url": "",
"updateJSON": "",
"logoFile": "${logo_path}"
}]
+6
View File
@@ -0,0 +1,6 @@
{
"pack": {
"description": "${mod_name} Resources",
"pack_format": 3
}
}
@@ -1,15 +1,14 @@
package com.seibel.distanthorizons.common;
import com.mojang.brigadier.CommandDispatcher;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
import com.seibel.distanthorizons.common.commands.CommandInitializer;
import com.seibel.distanthorizons.common.wrappers.DependencySetup;
import com.seibel.distanthorizons.common.wrappers.gui.DhDebugScreenEntry;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
import com.seibel.distanthorizons.core.Initializer;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
@@ -30,7 +29,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccesso
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import com.seibel.distanthorizons.core.logging.DhLogger;
@@ -39,6 +37,11 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
#if MC_VER > MC_1_12_2
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.commands.CommandSourceStack;
#endif
/**
* Base for all mod loader initializers
* and handles most setup.
@@ -62,7 +65,9 @@ public abstract class AbstractModInitializer
protected abstract IEventProxy createServerProxy(boolean isDedicated);
protected abstract void initializeModCompat();
#if MC_VER > MC_1_12_2
protected abstract void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler);
#endif
protected abstract void subscribeClientStartedEvent(Runnable eventHandler);
protected abstract void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler);
@@ -95,7 +100,9 @@ public abstract class AbstractModInitializer
// Client uses config for auto-updater, so it's initialized here instead of post-init stage
this.initConfig();
logModIncompatibilityWarnings(); // needs to be called after config loading
logIncompatibilityWarnings(); // needs to be called after config loading
setUnsupportedConfigsBasedOnMcVersion();
Initializer.postConfigInit();
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
@@ -129,21 +136,33 @@ public abstract class AbstractModInitializer
this.initializeModCompat();
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized, adding event subscribers...");
#if MC_VER > MC_1_12_2
this.commandInitializer = new CommandInitializer();
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer.initCommands(dispatcher); });
#endif
this.subscribeServerStartingEvent(server ->
{
MinecraftServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server;
this.initConfig();
Initializer.postConfigInit();
this.postInit();
this.postServerInit();
#if MC_VER > MC_1_12_2
this.commandInitializer.onServerReady();
#endif
this.checkForUpdates();
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized at " + server.getServerDirectory());
String serverFolderPath;
#if MC_VER <= MC_1_12_2
serverFolderPath = server.getDataDirectory() + "";
#else
serverFolderPath = server.getServerDirectory() + "";
#endif
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized at " + serverFolderPath);
});
}
@@ -159,7 +178,7 @@ public abstract class AbstractModInitializer
private void startup()
{
DependencySetup.createSharedBindings();
SharedApi.init();
Initializer.preConfigInit();
this.createInitialSharedBindings();
}
@@ -261,9 +280,9 @@ public abstract class AbstractModInitializer
//==================================//
// mod partial compatibility checks //
//==================================//
//======================//
// compatibility checks //
//======================//
//region
/**
@@ -272,7 +291,7 @@ public abstract class AbstractModInitializer
* This method will log (and display to chat if enabled)
* these warnings and potential fixes.
*/
private static void logModIncompatibilityWarnings()
private static void logIncompatibilityWarnings()
{
boolean showChatWarnings = Config.Common.Logging.Warning.showModCompatibilityWarningsOnStartup.get();
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
@@ -366,17 +385,17 @@ public abstract class AbstractModInitializer
if (iris != null)
{
// get the currently selected rendering API
EDhApiRenderApi renderApi = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
if (renderApi == EDhApiRenderApi.AUTO)
EDhApiRenderingEngine renderApi = Config.Client.Advanced.Graphics.Experimental.renderingEngine.get();
if (renderApi == EDhApiRenderingEngine.AUTO)
{
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
renderApi = versionConstants.getDefaultRenderingApi();
renderApi = versionConstants.getDefaultRenderingEngine();
}
// Iris only supports native OpenGL
if (renderApi != EDhApiRenderApi.OPEN_GL)
if (renderApi != EDhApiRenderingEngine.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 the DH config file.";
String irisUnsupportedMessage = "Iris doesn't support DH when using the ["+ EDhApiRenderingEngine.BLAZE_3D+"] rendering engine, this will need to be fixed on Iris end. As a temporary fix please change the rendering engine to ["+ EDhApiRenderingEngine.OPEN_GL+"] in the DH config file.";
LOGGER.fatal(irisUnsupportedMessage);
NativeDialogUtil.showDialog(ModInfo.READABLE_NAME, irisUnsupportedMessage, "ok", "error");
@@ -391,6 +410,24 @@ public abstract class AbstractModInitializer
}
/**
* Some Minecraft versions don't support all
* DH options.
* In that case we need to override what options are available.
*/
private static void setUnsupportedConfigsBasedOnMcVersion()
{
#if MC_VER <= MC_1_12_2
Config.Client.Advanced.Graphics.Experimental.renderingEngine.setMcVersionOverrideValue(EDhApiRenderingEngine.OPEN_GL);
Config.Client.Advanced.Graphics.Quality.vanillaFadeMode.setMcVersionOverrideValue(EDhApiMcRenderingFadeMode.NONE);
Config.Common.WorldGenerator.distantGeneratorMode.setMcVersionOverrideValue(EDhApiDistantGeneratorMode.INTERNAL_SERVER);
#elif MC_VER <= MC_1_21_10
Config.Client.Advanced.Graphics.Experimental.renderingEngine.setMcVersionOverrideValue(EDhApiRenderingEngine.OPEN_GL);
#else
#endif
}
//endregion
@@ -12,10 +12,17 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSende
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import io.netty.buffer.ByteBufUtil;
#if MC_VER <= MC_1_12_2
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.PacketBuffer;
#else
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
#endif
#if MC_VER <= MC_1_21_10
#if MC_VER <= MC_1_12_2
import net.minecraft.util.ResourceLocation;
#elif MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
@@ -30,7 +37,9 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
.fileLevelConfig(Config.Common.Logging.logNetworkEventToFile)
.build();
#if MC_VER <= MC_1_20_6
#if MC_VER <= MC_1_12_2
public static final String WRAPPER_PACKET_RESOURCE = ModInfo.RESOURCE_NAMESPACE + ModInfo.WRAPPER_PACKET_PATH;
#elif MC_VER <= MC_1_20_6
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
#elif MC_VER <= MC_1_21_10
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
@@ -52,14 +61,28 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
@Override
public final void sendToClient(IServerPlayerWrapper serverPlayer, AbstractNetworkMessage message)
{
#if MC_VER <= MC_1_12_2
this.sendToClient((EntityPlayerMP) serverPlayer.getWrappedMcObject(), message);
#else
this.sendToClient((ServerPlayer) serverPlayer.getWrappedMcObject(), message);
#endif
}
#if MC_VER <= MC_1_12_2
public abstract void sendToClient(EntityPlayerMP serverPlayer, AbstractNetworkMessage message);
#else
public abstract void sendToClient(ServerPlayer serverPlayer, AbstractNetworkMessage message);
#endif
@Override
public abstract void sendToServer(AbstractNetworkMessage message);
#if MC_VER <= MC_1_12_2
public AbstractNetworkMessage decodeMessage(PacketBuffer in)
#else
public AbstractNetworkMessage decodeMessage(FriendlyByteBuf in)
#endif
{
AbstractNetworkMessage message = null;
@@ -100,7 +123,11 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
}
}
#if MC_VER <= MC_1_12_2
public void encodeMessage(PacketBuffer out, AbstractNetworkMessage message)
#else
public void encodeMessage(FriendlyByteBuf out, AbstractNetworkMessage message)
#endif
{
// This is intentionally unhandled, because errors related to this are unlikely to appear in wild
Objects.requireNonNull(message);
@@ -1,5 +1,9 @@
package com.seibel.distanthorizons.common.commands;
#if MC_VER <= MC_1_12_2
public abstract class AbstractCommand {}
#else
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
@@ -100,3 +104,4 @@ public abstract class AbstractCommand
}
}
#endif
@@ -1,12 +1,26 @@
package com.seibel.distanthorizons.common.commands;
#if MC_VER <= MC_1_12_2
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.types.AbstractConfigBase;
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommand;
import net.minecraft.command.ICommandSender;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.text.TextComponentString;
#else
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.minecraft.commands.CommandSourceStack;
import static net.minecraft.commands.Commands.literal;
#endif
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_CODEC_CRASH_MESSAGE;
import static net.minecraft.commands.Commands.literal;
#if MC_VER <= MC_1_21_10
#else
@@ -25,6 +39,70 @@ public class CommandInitializer
#endif
#if MC_VER <= MC_1_12_2
public static ICommand initCommands()
{
return new CommandBase()
{
@Override
public String getName() { return "dh"; }
@Override
public String getUsage(ICommandSender sender) { return "/dh <debug|config|pregen>"; }
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] args)
{
if (args.length == 0)
{
if (DEBUG_CODEC_CRASH_MESSAGE)
{
sender.sendMessage(new TextComponentString("Usage: /dh <debug|config|crash|pregen>"));
}
else
{
sender.sendMessage(new TextComponentString("Usage: /dh <debug|config|pregen"));
}
return;
}
switch (args[0])
{
case "debug":
DebugCommand debugCommand = new DebugCommand();
debugCommand.execute(sender);
break;
case "config":
ConfigCommand configCommand = new ConfigCommand();
configCommand.execute(sender, args);
break;
case "crash":
if (DEBUG_CODEC_CRASH_MESSAGE)
{
CrashCommand crashCommand = new CrashCommand();
crashCommand.execute(sender, args);
}
break;
case "pregen":
if (!server.isDedicatedServer())
{
sender.sendMessage(new TextComponentString("Pregen command is only available on dedicated servers"));
break;
}
PregenCommand pregenCommand = new PregenCommand();
pregenCommand.execute(server, sender, args);
break;
default:
sender.sendMessage(new TextComponentString("Unknown subcommand: " + args[0]));
}
}
};
}
#else
/**
* A received command dispatcher, which is held until the server is ready to initialize the commands.
*/
@@ -80,5 +158,5 @@ public class CommandInitializer
commandDispatcher.register(builder);
}
#endif
}
@@ -1,13 +1,25 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.arguments.*;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.types.AbstractConfigBase;
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
#if MC_VER <= MC_1_12_2
import net.minecraft.command.ICommandSender;
import net.minecraft.util.text.TextComponentString;
#else
import com.mojang.brigadier.arguments.*;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.commands.CommandSourceStack;
import static com.mojang.brigadier.arguments.DoubleArgumentType.doubleArg;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static net.minecraft.commands.Commands.argument;
import static net.minecraft.commands.Commands.literal;
#endif
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -16,16 +28,75 @@ import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.ToIntBiFunction;
import static com.mojang.brigadier.arguments.DoubleArgumentType.doubleArg;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static net.minecraft.commands.Commands.argument;
import static net.minecraft.commands.Commands.literal;
/**
* Command for managing config.
*/
public class ConfigCommand extends AbstractCommand
{
#if MC_VER <= MC_1_12_2
@SuppressWarnings({"unchecked", "rawtypes"})
private static void setConfigValue(ConfigEntry<?> configEntry, String value)
{
Class<?> type = configEntry.getType();
if (type == Boolean.class) ((ConfigEntry) configEntry).set(Boolean.parseBoolean(value));
else if (type == Integer.class) ((ConfigEntry) configEntry).set(Integer.parseInt(value));
else if (type == Double.class) ((ConfigEntry) configEntry).set(Double.parseDouble(value));
else if (type == Float.class) ((ConfigEntry) configEntry).set(Float.parseFloat(value));
else if (type == Long.class) ((ConfigEntry) configEntry).set(Long.parseLong(value));
else if (type == String.class) ((ConfigEntry) configEntry).set(value);
else if (type.isEnum()) ((ConfigEntry) configEntry).set(Enum.valueOf((Class<Enum>) type, value));
else throw new RuntimeException("Unsupported config type: " + type.getSimpleName());
}
public void execute(ICommandSender sender, String[] args)
{
if (args.length < 2)
{
sender.sendMessage(new TextComponentString("Usage: /dh config <name> [value]"));
return;
}
String configName = args[1];
AbstractConfigBase<?> found = null;
for (AbstractConfigBase<?> entry : ConfigHandler.INSTANCE.configBaseList)
{
if (entry instanceof ConfigEntry && configName.equals(((ConfigEntry<?>) entry).getChatCommandName()))
{
found = entry;
break;
}
}
if (found == null)
{
sender.sendMessage(new TextComponentString("Unknown config: " + configName));
return;
}
ConfigEntry<?> configEntry = (ConfigEntry<?>) found;
if (args.length == 2)
{
sender.sendMessage(new TextComponentString("Current value of " + configName + " is " + configEntry.get()));
}
else
{
String value = args[2];
try
{
setConfigValue(configEntry, value);
sender.sendMessage(new TextComponentString("Changed " + configName + " to " + value));
}
catch (Exception e)
{
sender.sendMessage(new TextComponentString("Invalid value: " + value));
}
}
}
#else
private static final List<CommandArgumentData<?>> commandArguments = Arrays.asList(
new CommandArgumentData<>(Integer.class, configEntry -> integer(configEntry.getMin(), configEntry.getMax()), IntegerArgumentType::getInteger),
new CommandArgumentData<>(Double.class, configEntry -> doubleArg(configEntry.getMin(), configEntry.getMax()), DoubleArgumentType::getDouble),
@@ -150,5 +221,6 @@ public class ConfigCommand extends AbstractCommand
}
}
#endif
}
}
@@ -1,15 +1,60 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerState;
import com.seibel.distanthorizons.core.network.messages.base.CodecCrashMessage;
#if MC_VER <= MC_1_12_2
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.text.TextComponentString;
#else
import net.minecraft.commands.CommandSourceStack;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import static net.minecraft.commands.Commands.literal;
#endif
public class CrashCommand extends AbstractCommand
{
#if MC_VER <= MC_1_12_2
public void execute(ICommandSender sender, String[] args)
{
if (!(sender instanceof EntityPlayerMP))
{
sender.sendMessage(new TextComponentString("This command can only be run by a player"));
return;
}
if (args.length < 2)
{
sender.sendMessage(new TextComponentString("Usage: /dh crash <encode|decode>"));
return;
}
if (SharedApi.tryGetDhServerWorld() == null) return;
ServerPlayerState serverPlayerState = SharedApi.tryGetDhServerWorld()
.getServerPlayerStateManager()
.getConnectedPlayer(ServerPlayerWrapper.getWrapper((EntityPlayerMP) sender));
if (serverPlayerState == null) return;
switch (args[1])
{
case "encode":
serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.ENCODE));
break;
case "decode":
serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.DECODE));
break;
default:
sender.sendMessage(new TextComponentString("Usage: /dh crash <encode|decode>"));
}
}
#else
@Override
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
{
@@ -40,5 +85,6 @@ public class CrashCommand extends AbstractCommand
return 1;
}));
}
#endif
}
@@ -1,25 +1,44 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
#if MC_VER <= MC_1_12_2
import net.minecraft.command.ICommandSender;
import net.minecraft.util.text.TextComponentString;
#else
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.minecraft.commands.CommandSourceStack;
import static net.minecraft.commands.Commands.literal;
#endif
import java.util.ArrayList;
import java.util.List;
import static net.minecraft.commands.Commands.literal;
public class DebugCommand extends AbstractCommand
{
private static String getDebugString()
{
List<String> lines = new ArrayList<>();
F3Screen.addStringToDisplay(lines);
return String.join("\n", lines);
}
#if MC_VER > MC_1_12_2
@Override
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
{
return literal("debug")
.executes(c -> {
List<String> lines = new ArrayList<>();
F3Screen.addStringToDisplay(lines);
return this.sendSuccessResponse(c, String.join("\n", lines), false);
});
return literal("debug")
.executes(c -> {
return this.sendSuccessResponse(c, getDebugString(), false);
});
}
#else
public void execute(ICommandSender sender)
{
sender.sendMessage(new TextComponentString(getDebugString()));
}
#endif
}
@@ -1,27 +1,36 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.generation.PregenManager;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
import com.seibel.distanthorizons.core.world.DhServerWorld;
#if MC_VER <= MC_1_12_2
import net.minecraft.command.ICommandSender;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.WorldServer;
#else
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.arguments.DimensionArgument;
import net.minecraft.commands.arguments.coordinates.ColumnPosArgument;
import net.minecraft.server.level.ColumnPos;
import net.minecraft.server.level.ServerLevel;
import java.util.Objects;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static net.minecraft.commands.Commands.argument;
import static net.minecraft.commands.Commands.literal;
#endif
import java.util.Objects;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
public class PregenCommand extends AbstractCommand
{
@@ -31,6 +40,101 @@ public class PregenCommand extends AbstractCommand
return world.getPregenManager();
}
#if MC_VER <= MC_1_12_2
public void execute(MinecraftServer server, ICommandSender sender, String[] args)
{
if (args.length < 2)
{
sender.sendMessage(new TextComponentString("Usage: /dh pregen <status|start|stop>"));
return;
}
switch (args[1])
{
case "status":
{
String statusString = this.getPregenManager().getStatusString();
sender.sendMessage(new TextComponentString(
statusString != null ? statusString : "Pregen is not running"));
break;
}
case "start":
{
if (args.length < 5)
{
sender.sendMessage(new TextComponentString("Usage: /dh pregen start <dimension> <x> <z> <chunkRadius>"));
return;
}
try
{
String dimensionName = args[2];
int x = Integer.parseInt(args[3]);
int z = Integer.parseInt(args[4]);
int chunkRadius = args.length >= 6 ? Integer.parseInt(args[5]) : 32;
// find the world by dimension name
WorldServer world = null;
for (WorldServer w : server.worlds)
{
if (w.provider.getDimensionType().getName().equals(dimensionName))
{
world = w;
break;
}
}
if (world == null)
{
sender.sendMessage(new TextComponentString("Unknown dimension: " + dimensionName));
return;
}
sender.sendMessage(new TextComponentString("Starting pregen. Progress will be in the server console."));
final ICommandSender finalSender = sender;
CompletableFuture<Void> future = this.getPregenManager().startPregen(
ServerLevelWrapper.getWrapper(world),
new DhBlockPos2D(x, z),
chunkRadius
);
future.whenComplete((result, throwable) -> {
if (throwable instanceof CancellationException)
{
finalSender.sendMessage(new TextComponentString("Pregen is cancelled"));
return;
}
else if (throwable != null)
{
finalSender.sendMessage(new TextComponentString("Pregen failed: " + throwable.getMessage()));
return;
}
finalSender.sendMessage(new TextComponentString("Pregen is complete"));
});
}
catch (NumberFormatException e)
{
sender.sendMessage(new TextComponentString("Invalid number format"));
}
break;
}
case "stop":
{
CompletableFuture<Void> runningPregen = this.getPregenManager().getRunningPregen();
if (runningPregen == null)
{
sender.sendMessage(new TextComponentString("Pregen is not running"));
return;
}
runningPregen.cancel(true);
break;
}
default:
sender.sendMessage(new TextComponentString("Unknown subcommand: " + args[1]));
}
}
#else
@Override
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
{
@@ -110,5 +214,5 @@ public class PregenCommand extends AbstractCommand
runningPregen.cancel(true);
return 1;
}
#endif
}
@@ -1,6 +1,7 @@
package com.seibel.distanthorizons.common.commonMixins;
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
import com.seibel.distanthorizons.common.wrappers.gui.DhScreenUtil;
import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
@@ -9,19 +10,25 @@ import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import net.minecraft.client.Minecraft;
#if MC_VER <= MC_1_12_2
import net.minecraft.client.gui.GuiMainMenu;
#else
import net.minecraft.client.gui.screens.TitleScreen;
#endif
import java.util.ArrayList;
public class DhUpdateScreenBase
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
#if MC_VER <= MC_1_12_2
private static final Minecraft MC = Minecraft.getMinecraft();
#else
private static final Minecraft MC = Minecraft.getInstance();
#endif
public static void tryShowUpdateScreenAndRunAutoUpdateStartup(Runnable runnable)
{
@@ -68,19 +75,31 @@ public class DhUpdateScreenBase
}
try
// running on the render thread is required since setting the MC screen may trigger
// before its allowed, silently failing
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Update Screen", () ->
{
MC.setScreen(new UpdateModScreen(
new TitleScreen(false),
versionId
));
}
catch (Exception e)
{
// info instead of error since this can be ignored and probably just means
// there isn't a new DH version available
LOGGER.info("Unable to show DH update screen, reason: ["+e.getMessage()+"].");
}
try
{
#if MC_VER <= MC_1_12_2
DhScreenUtil.showScreen(new UpdateModScreen(
new TitleScreen(false),
versionId
));
#else
DhScreenUtil.setScreen(new UpdateModScreen(
new TitleScreen(false),
versionId
));
#endif
}
catch (Exception e)
{
// info instead of error since this can be ignored and probably just means
// there isn't a new DH version available
LOGGER.error("Unable to show DH update screen, reason: ["+e.getMessage()+"].");
}
});
};
runnable.run();
}
@@ -6,15 +6,23 @@ import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
#if MC_VER <= MC_1_12_2
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.Chunk;
#else
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk;
#endif
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public class MixinChunkMapCommon
{
#if MC_VER <= MC_1_12_2
public static void onChunkSave(WorldServer level, Chunk chunk)
#else
public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
#endif
{
IServerLevelWrapper levelWrapper = ServerLevelWrapper.getWrapper(level);
@@ -37,7 +45,7 @@ public class MixinChunkMapCommon
// is this chunk being saved to disk?
boolean savingChunkToDisk = ci.getReturnValue();
boolean savingChunkToDisk = #if MC_VER <= MC_1_12_2 true #else ci.getReturnValue() #endif;
// true means a chunk was saved to disk
if (!savingChunkToDisk)
{
@@ -50,7 +58,12 @@ public class MixinChunkMapCommon
// MC has a tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks)
// this logic should prevent that from happening
#if MC_VER <= MC_1_17_1
#if MC_VER <= MC_1_12_2
if (!chunk.isTerrainPopulated() || !chunk.isLightPopulated())
{
return;
}
#elif MC_VER <= MC_1_17_1
if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
{
return;
@@ -67,7 +80,12 @@ public class MixinChunkMapCommon
// biome validation //
// some chunks may be missing their biomes, which cause issues when attempting to save them
#if MC_VER <= MC_1_17_1
#if MC_VER <= MC_1_12_2
if (chunk. getBiomeArray() == null)
{
return;
}
#elif MC_VER <= MC_1_17_1
if (chunk.getBiomes() == null)
{
return;
@@ -0,0 +1,127 @@
package com.seibel.distanthorizons.common.commonMixins;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
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.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.Minecraft;
#if MC_VER <= MC_1_12_2
#else
import net.minecraft.client.Camera;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
#endif
#if MC_VER <= MC_1_12_2
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.init.MobEffects;
#elif MC_VER < MC_1_17_1
import net.minecraft.world.level.material.FluidState;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.FogRenderer.FogMode;
import com.mojang.blaze3d.systems.RenderSystem;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
#elif MC_VER < MC_1_21_3
import net.minecraft.world.level.material.FogType;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.FogRenderer.FogMode;
import com.mojang.blaze3d.systems.RenderSystem;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
#elif MC_VER < MC_1_21_6
import net.minecraft.world.level.material.FogType;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.mojang.blaze3d.shaders.FogShape;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.FogRenderer.FogMode;
import net.minecraft.client.renderer.FogParameters;
import org.joml.Vector4f;
import com.mojang.blaze3d.systems.RenderSystem;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
#else
import net.minecraft.world.level.material.FogType;
#endif
public class MixinVanillaFogCommon
{
#if MC_VER <= MC_1_12_2
public static boolean cancelFog(int startCoords, Minecraft mc)
#elif MC_VER < MC_1_21_6
public static boolean cancelFog(Camera camera, FogRenderer.FogMode fogMode)
#else
public static boolean cancelFog()
#endif
{
#if MC_VER <= MC_1_12_2
EntityPlayerSP entity = mc.player;
#elif MC_VER < MC_1_21_6
Entity entity = camera.getEntity();
#elif MC_VER <= MC_1_21_10
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
Entity entity = camera.getEntity();
#elif MC_VER <= MC_26_1_2
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
Entity entity = camera.entity();
#else
Camera camera = Minecraft.getInstance().gameRenderer.mainCamera();
Entity entity = camera.entity();
#endif
#if MC_VER <= MC_1_12_2
boolean cameraNotInFluid = cameraNotInFluid(mc);
#else
boolean cameraNotInFluid = cameraNotInFluid(camera);
#endif
#if MC_VER <= MC_1_12_2
boolean isSpecialFog = entity.isPotionActive(MobEffects.BLINDNESS);
#else
boolean isSpecialFog = (entity instanceof LivingEntity) && ((LivingEntity) entity).hasEffect(MobEffects.BLINDNESS);
#endif
boolean cancelFog = !isSpecialFog;
cancelFog = cancelFog && cameraNotInFluid;
#if MC_VER <= MC_1_12_2
cancelFog = cancelFog && startCoords == 0; // 0 = terrain fog
#elif MC_VER < MC_1_21_6
cancelFog = cancelFog && (fogMode == FogRenderer.FogMode.FOG_TERRAIN);
#endif
cancelFog = cancelFog && !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial();
cancelFog = cancelFog && !Config.Client.Advanced.Graphics.Fog.enableVanillaFog.get();
return cancelFog;
}
#if MC_VER <= MC_1_12_2
private static boolean cameraNotInFluid(Minecraft mc)
#else
private static boolean cameraNotInFluid(Camera camera)
#endif
{
#if MC_VER <= MC_1_12_2
boolean cameraNotInFluid = mc.getRenderViewEntity() != null && !mc.world.getBlockState(mc.getRenderViewEntity().getPosition()).getMaterial().isLiquid();
#elif MC_VER < MC_1_17_1
FluidState fluidState = camera.getFluidInCamera();
boolean cameraNotInFluid = fluidState.isEmpty();
#else
FogType fogTypes = camera.getFluidInCamera();
boolean cameraNotInFluid = fogTypes == FogType.NONE;
#endif
return cameraNotInFluid;
}
}
@@ -26,34 +26,30 @@ public class BlazeDebugWireframeRenderer {}
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.BlazeVertexFormatBuilder;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import net.minecraft.resources.Identifier;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Handles rendering the wireframe particles
@@ -64,11 +60,10 @@ public class BlazeDebugWireframeRenderer extends AbstractDebugWireframeRenderer
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
public static BlazeDebugWireframeRenderer INSTANCE = new BlazeDebugWireframeRenderer();
/** A box from 0,0,0 to 1,1,1 */
private static final float[] BOX_VERTICES = {
//region
@@ -103,6 +98,7 @@ public class BlazeDebugWireframeRenderer extends AbstractDebugWireframeRenderer
//endregion
};
private static final Mat4f TRANSFORM_MATRIX = new Mat4f();
@@ -114,7 +110,7 @@ public class BlazeDebugWireframeRenderer extends AbstractDebugWireframeRenderer
private GpuBuffer boxVertexBuffer;
private GpuBuffer boxIndexBuffer;
private GpuBuffer uniformBuffer;
private final BlazeUniformBufferWrapper uniformBufferWrapper = new BlazeUniformBufferWrapper("debugWireframeUniformBlock");
@@ -143,7 +139,14 @@ public class BlazeDebugWireframeRenderer extends AbstractDebugWireframeRenderer
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(true);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
if (RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.FORWARD_Z)
{
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
}
else
{
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.GREATER);
}
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.WIREFRAME);
@@ -155,7 +158,7 @@ public class BlazeDebugWireframeRenderer extends AbstractDebugWireframeRenderer
pipelineBuilder.withUniformBuffer("uniformBlock");
VertexFormat vertexFormat = VertexFormat.builder()
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
.build();
pipelineBuilder.withVertexFormat(vertexFormat);
@@ -181,7 +184,7 @@ public class BlazeDebugWireframeRenderer extends AbstractDebugWireframeRenderer
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int size = BOX_VERTICES.length * Float.BYTES;
this.boxVertexBuffer = GPU_DEVICE.createBuffer(() -> "distantHorizons:McDebugWireframeBox", usage, size);
this.boxVertexBuffer = GPU_DEVICE.createBuffer(() -> "distantHorizons:DebugWireframeBox", usage, size);
{
int length = BOX_VERTICES.length * Float.BYTES;
@@ -251,14 +254,7 @@ public class BlazeDebugWireframeRenderer extends AbstractDebugWireframeRenderer
// uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putMat4f() // uTransform
.putVec4() // uColor
.get();
// create data //
Vec3d camPos = MC_RENDER.getCameraExactPosition();
Vec3f camPosFloatThisFrame = new Vec3f((float) camPos.x, (float) camPos.y, (float) camPos.z);
@@ -271,57 +267,43 @@ public class BlazeDebugWireframeRenderer extends AbstractDebugWireframeRenderer
box.maxPos.y - box.minPos.y,
box.maxPos.z - box.minPos.z));
Mat4f transformMatrix = this.dhMvmProjMatrixThisFrame.copy();
transformMatrix.multiply(boxTransform);
TRANSFORM_MATRIX.set(this.dhMvmProjMatrixThisFrame);
TRANSFORM_MATRIX.multiply(boxTransform);
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putMat4f(transformMatrix.createJomlMatrix()) // uTransform
.putVec4(
this.uniformBufferWrapper
.putMat4f(TRANSFORM_MATRIX) // uTransform
.putVec4f(
box.color.getRed() / 255.0f,
box.color.getGreen() / 255.0f,
box.color.getBlue() / 255.0f,
box.color.getAlpha() / 255.0f) // uColor
.get()
.finishAndUpload()
;
this.uniformBuffer = BlazeUniformUtil.createBuffer("uniformBlock", uniformBufferSize, this.uniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.uniformBuffer, 0, uniformBufferSize);
commandEncoder.writeToBuffer(bufferSlice, buffer);
}
// render //
//try (RenderPass renderPass = commandEncoder.createRenderPass(
// this::getRenderPassName,
// BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
// /*optionalClearColorAsInt*/ OptionalInt.empty(),
// BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
// /*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
//{
// // Bind instance data //
// renderPass.setUniform("uniformBlock", this.uniformBuffer);
//
// renderPass.setPipeline(this.pipeline);
// renderPass.setIndexBuffer(this.boxIndexBuffer, VertexFormat.IndexType.INT);
//
// renderPass.setVertexBuffer(0, this.boxVertexBuffer);
//
// renderPass.drawIndexed(
// /*indexStart*/ 0,
// /*firstIndex*/0,
// /*indexCount*/BOX_OUTLINE_INDICES.length,
// /*instanceCount*/1);
//}
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper,
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper))
{
// Bind instance data //
renderPassWrapper.setUniform("uniformBlock", this.uniformBufferWrapper);
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.setIndexBuffer(this.boxIndexBuffer);
renderPassWrapper.setVertexBuffer(this.boxVertexBuffer);
renderPassWrapper.drawIndexed(BOX_OUTLINE_INDICES.length);
}
}
private String getRenderPassName() { return "distantHorizons:McDebugRenderer"; }
private String getRenderPassName() { return "distantHorizons:DebugRenderer"; }
//endregion
@@ -24,17 +24,10 @@ public class BlazeDhGenericObjectRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
@@ -43,21 +36,27 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericObjectRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderCleanupEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderSetupEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import com.seibel.distanthorizons.common.render.blaze.objects.BlazeGenericObjectVertexContainer;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.BlazeVertexFormatBuilder;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
import com.seibel.distanthorizons.core.util.LodUtil;
@@ -68,15 +67,10 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrap
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.resources.Identifier;
import java.awt.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -90,6 +84,7 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
@@ -102,6 +97,10 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
*/
public static final boolean RENDER_DEBUG_OBJECTS = false;
private static final DhApiBeforeGenericObjectRenderEvent.EventParam EVENT_PARAM = new DhApiBeforeGenericObjectRenderEvent.EventParam();
private final ConcurrentHashMap<Long, RenderableBoxGroup> boxGroupById = new ConcurrentHashMap<>();
@@ -110,7 +109,7 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
private RenderPipeline pipeline;
private GpuBuffer vertUniformBuffer;
private final BlazeUniformBufferWrapper vertUniformBufferWrapper = new BlazeUniformBufferWrapper("vertUniformBlock");
@@ -142,7 +141,14 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
{
pipelineBuilder.withFaceCulling(true);
pipelineBuilder.withDepthWrite(true);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
if (RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.FORWARD_Z)
{
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
}
else
{
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.GREATER);
}
pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT); // TRANSLUCENT = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
@@ -155,7 +161,7 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
pipelineBuilder.withUniformBuffer("vertUniformBlock");
VertexFormat vertexFormat = VertexFormat.builder()
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
.add("aColor", BlazeDhVertexFormatUtil.RGBA_UBYTE_COLOR)
.add("aMaterial", BlazeDhVertexFormatUtil.IRIS_MATERIAL)
@@ -342,7 +348,7 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
this.init();
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam.apiCopy);
Vec3d camPos = MC_RENDER.getCameraExactPosition();
@@ -388,7 +394,8 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
}
// allow API users to cancel this object's rendering
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
EVENT_PARAM.update(renderEventParam, boxGroup);
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, EVENT_PARAM);
if (cancelRendering)
{
continue;
@@ -414,28 +421,6 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
// 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);
@@ -444,31 +429,29 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putIVec3(
this.vertUniformBufferWrapper
.putVec3i(
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
) // uOffsetChunk
.putVec3(
.putVec3f(
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
) // uOffsetSubChunk
.putIVec3(
.putVec3i(
LodUtil.getChunkPosFromDouble(camPos.x),
LodUtil.getChunkPosFromDouble(camPos.y),
LodUtil.getChunkPosFromDouble(camPos.z)
) // uCameraPosChunk
.putVec3(
.putVec3f(
LodUtil.getSubChunkPosFromDouble(camPos.x),
LodUtil.getSubChunkPosFromDouble(camPos.y),
LodUtil.getSubChunkPosFromDouble(camPos.z)
) // uCameraPosSubChunk
.putMat4f(projectionMvmMatrix.createJomlMatrix()) // uProjectionMvm
.putMat4f(projectionMvmMatrix) // uProjectionMvm
.putInt(boxGroup.getSkyLight()) // uSkyLight
.putInt(boxGroup.getBlockLight()) // uBlockLight
@@ -479,13 +462,8 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
.putFloat(shading.top)
.putFloat(shading.bottom)
.get()
.finishAndUpload()
;
this.vertUniformBuffer = BlazeUniformUtil.createBuffer("vertUniformBlock", uniformBufferSize, this.vertUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
@@ -519,7 +497,7 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
//endregion
}
}
private String getRenderPassName() { return "distantHorizons:McGenericObjectRenderer"; }
private String getRenderPassName() { return "distantHorizons:GenericObjectRenderer"; }
//endregion
@@ -535,12 +513,10 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
RenderableBoxGroup boxGroup,
IProfilerWrapper profiler)
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper,
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper))
{
// update instance data //
@@ -549,30 +525,26 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
renderPass.bindTexture("uLightMap", lightmapTextureViewWrapper.textureView, lightmapTextureViewWrapper.textureSampler);
renderPassWrapper.bindTexture("uLightMap", lightmapTextureViewWrapper);
// Bind instance data //
renderPass.setUniform("vertUniformBlock", this.vertUniformBuffer);
renderPassWrapper.setUniform("vertUniformBlock", this.vertUniformBufferWrapper);
// set pipeline
renderPass.setPipeline(this.pipeline);
renderPass.setIndexBuffer(container.indexGpuBuffer, VertexFormat.IndexType.INT);
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.setIndexBuffer(container.indexGpuBuffer);
renderPass.setVertexBuffer(0, container.vboGpuBuffer);
renderPassWrapper.setVertexBuffer(container.vboGpuBuffer);
// Draw instanced
if (container.uploadedBoxCount > 0)
{
renderPass.drawIndexed(
/*indexStart*/ 0,
/*firstIndex*/0,
/*indexCount*/container.uploadedBoxCount * 36, // 36 = 6 faces * 6 verticies per face
/*instanceCount*/1);
// 36 = 6 faces * 6 verticies per face
renderPassWrapper.drawIndexed(container.uploadedBoxCount * 36);
}
}
}
@@ -615,5 +587,27 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
// close is called outside the render thread and buffer closing must be done on the render thread
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Generic Obj Cleanup", () ->
{
if (this.vertUniformBufferWrapper != null)
{
this.vertUniformBufferWrapper.close();
}
});
}
//endregion
}
#endif
@@ -10,8 +10,10 @@ import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterCo
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.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
@@ -28,6 +30,7 @@ public class BlazeDhMetaRenderer implements IDhMetaRenderer
private BlazeDhApplyRenderer applyRenderer;
private final float clearDepth;
public final BlazeTextureWrapper dhDepthTextureWrapper = BlazeTextureWrapper.createDepth("DhDepthTexture");
public final BlazeTextureWrapper dhColorTextureWrapper = BlazeTextureWrapper.createColor("DhColorTexture");
@@ -41,6 +44,9 @@ public class BlazeDhMetaRenderer implements IDhMetaRenderer
private BlazeDhMetaRenderer()
{
AbstractDhRenderApiDefinition renderApiDefinition = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
this.clearDepth = renderApiDefinition.getRenderDepth().farDepth;
this.applyRenderer = new BlazeDhApplyRenderer(
"dh_apply_to_mc",
null,
@@ -86,7 +92,7 @@ public class BlazeDhMetaRenderer implements IDhMetaRenderer
@Override
public void applyToMcTexture(RenderParams renderParams)
{
GpuTexture mcColorTexture = Minecraft.getInstance().getMainRenderTarget().getColorTexture();
GpuTexture mcColorTexture = MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture();
this.applyRenderer.render(this.dhColorTextureWrapper.texture, this.dhDepthTextureWrapper.texture, mcColorTexture);
}
@@ -102,7 +108,7 @@ public class BlazeDhMetaRenderer implements IDhMetaRenderer
@Override
public void clearDhDepthAndColorTextures(RenderParams renderParams)
{
this.dhDepthTextureWrapper.clearDepth(1.0f);
this.dhDepthTextureWrapper.clearDepth(this.clearDepth);
Color color = MC_RENDER.getSkyColor();
this.dhColorTextureWrapper.clearColor(ColorUtil.toColorInt(color));
@@ -111,5 +117,6 @@ public class BlazeDhMetaRenderer implements IDhMetaRenderer
//endregion
}
#endif
@@ -5,6 +5,8 @@ public class BlazeDhRenderApiDefinition {}
#else
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
import com.seibel.distanthorizons.common.render.blaze.objects.BlazeGenericObjectVertexContainer;
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeDhFarFadeRenderer;
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeDhFogRenderer;
@@ -13,6 +15,8 @@ import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeVanill
import com.seibel.distanthorizons.common.render.blaze.test.BlazeDhTestTriangleRenderer;
import com.seibel.distanthorizons.common.render.blaze.wrappers.buffer.BlazeVertexBufferWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeLodUniformBufferWrapper;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
@@ -20,6 +24,10 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodCont
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.*;
#if MC_VER <= MC_26_1_2
#else
#endif
public class BlazeDhRenderApiDefinition extends AbstractDhRenderApiDefinition
{
//=========//
@@ -27,7 +35,43 @@ public class BlazeDhRenderApiDefinition extends AbstractDhRenderApiDefinition
//=========//
//region
public String getApiName() { return "Blaze3D"; }
private final String apiName;
public String getApiName() { return this.apiName; }
public EDhRenderDepth getRenderDepth()
{
#if MC_VER <= MC_26_1_2
return EDhRenderDepth.FORWARD_Z;
#else
return EDhRenderDepth.REVERSE_Z;
#endif
}
private final EDhApiRenderingApi renderApi;
public EDhApiRenderingApi getRenderApi() { return renderApi; }
public boolean isNativeRenderer() { return false; }
//endregion
//=============//
// constructor //
//=============//
//region
public BlazeDhRenderApiDefinition()
{
#if MC_VER <= MC_26_1_2
renderApi = EDhApiRenderingApi.OPEN_GL;
#else
// use the same rendering API as Minecraft
this.renderApi = MinecraftRenderWrapper.INSTANCE.getMcRenderingApi();
#endif
this.apiName = "Blaze3D: " + this.getRenderApi();
}
//endregion
@@ -5,32 +5,31 @@ public class BlazeDhTerrainRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeBufferRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderPassEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.BlazeVertexFormatBuilder;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeLodUniformBufferWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.buffer.BlazeVertexBufferWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
@@ -38,34 +37,34 @@ import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTerrainRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import net.minecraft.resources.Identifier;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/** Renders rendering DH's LOD terrain. */
public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhTerrainRenderer INSTANCE = new BlazeDhTerrainRenderer();
private static final Vec3f MODEL_POS = new Vec3f();
/** single event object used to reduce GC pressure */
private static final DhApiBeforeBufferRenderEvent.EventParam BEFORE_BUFFER_RENDER_EVENT_PARAM = new DhApiBeforeBufferRenderEvent.EventParam();
private RenderPipeline opaquePipeline;
private RenderPipeline transparentPipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private GpuBuffer vertSharedUniformBuffer;
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("fragUniformBlock");
private final BlazeUniformBufferWrapper vertSharedUniformBufferWrapper = new BlazeUniformBufferWrapper("vertSharedUniformBlock");
@@ -85,14 +84,28 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
RenderPipelineBuilderWrapper opaquePipelineBuilder = new RenderPipelineBuilderWrapper();
RenderPipelineBuilderWrapper translucentPipelineBuilder = new RenderPipelineBuilderWrapper();
// apply shared options to both pipelines
for (int i = 0; i < 2; i++)
{
RenderPipelineBuilderWrapper pipelineBuilder = (i == 0)
? opaquePipelineBuilder
: translucentPipelineBuilder;
pipelineBuilder.withFaceCulling(true);
pipelineBuilder.withDepthWrite(true);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
if (RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.FORWARD_Z)
{
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
}
else
{
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.GREATER);
}
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("terrain");
pipelineBuilder.withSampler("uLightMap");
@@ -103,7 +116,7 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
pipelineBuilder.withUniformBuffer("vertSharedUniformBlock");
pipelineBuilder.withUniformBuffer("fragUniformBlock");
VertexFormat vertexFormat = VertexFormat.builder()
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
.add("vPosition", BlazeDhVertexFormatUtil.SHORT_XYZ_POS)
.add("meta", BlazeDhVertexFormatUtil.META)
.add("vColor", BlazeDhVertexFormatUtil.RGBA_UBYTE_COLOR)
@@ -119,15 +132,17 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
// opaque
{
pipelineBuilder.withoutBlend();
this.opaquePipeline = pipelineBuilder.build();
opaquePipelineBuilder.withName("opaque_terrain");
opaquePipelineBuilder.withoutBlend();
this.opaquePipeline = opaquePipelineBuilder.build();
}
// transparent
{
translucentPipelineBuilder.withName("transparent_terrain");
// TRANSLUCENT = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA);
pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT);
this.transparentPipeline = pipelineBuilder.build();
translucentPipelineBuilder.withBlend(BlendFunction.TRANSLUCENT);
this.transparentPipeline = translucentPipelineBuilder.build();
}
this.init = true;
@@ -160,7 +175,7 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
bufferContainer.uniformContainer.tryUpload();
bufferContainer.uniformContainer.tryUpload(bufferContainer);
}
}
@@ -183,53 +198,25 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
// upload data //
int uniformBufferSize = new Std140SizeCalculator()
.putInt() // uIsWhiteWorld
.putFloat() // uWorldYOffset
.putFloat() // uMircoOffset
.putFloat() // uEarthRadius
.putVec3() // uCameraPos
.putMat4f() // uCombinedMatrix
.get();
int i = Config.Client.Advanced.Debugging.enableWhiteWorld.get() ? 1 : 0;
ByteBuffer buffer = MemoryUtil.memAlloc(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
Std140Builder.intoBuffer(buffer)
.putInt(0) // uIsWhiteWorld
this.vertSharedUniformBufferWrapper
.putInt(i) // uIsWhiteWorld
.putFloat((float) renderEventParam.worldYOffset) // uWorldYOffset
.putFloat(0.01f) // uMircoOffset // 0.01 block offset
.putFloat(earthCurveRatio) // uEarthRadius
.putVec3(
.putVec3f(
(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);
.putMat4f(combinedMatrix) // uCombinedMatrix
.finishAndUpload();
}
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();
@@ -241,24 +228,15 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
// upload data //
ByteBuffer buffer = MemoryUtil.memAlloc(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
this.fragUniformBufferWrapper
.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()
.finishAndUpload()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
MemoryUtil.memFree(buffer);
}
@@ -267,25 +245,25 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
{
profiler.popPush("rendering");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam.apiCopy);
// create a render pass
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty())
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper,
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper)
)
{
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
renderPass.bindTexture("uLightMap", lightmapTextureViewWrapper.textureView, lightmapTextureViewWrapper.textureSampler);
renderPassWrapper.bindTexture("uLightMap", lightmapTextureViewWrapper);
// set pipeline
renderPass.setPipeline(opaquePass ? this.opaquePipeline : this.transparentPipeline);
renderPassWrapper.setPipeline(opaquePass ? this.opaquePipeline : this.transparentPipeline);
// shared uniforms
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setUniform("vertSharedUniformBlock", this.vertSharedUniformBuffer);
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
renderPassWrapper.setUniform("vertSharedUniformBlock", this.vertSharedUniformBufferWrapper);
@@ -309,7 +287,7 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
}
}
renderPass.setUniform("vertUniqueUniformBlock", uniformWrapper.gpuBuffer);
renderPassWrapper.setUniform("vertUniqueUniformBlock", uniformWrapper);
@@ -327,23 +305,20 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
// fire render event
{
Vec3d camPos = renderEventParam.exactCameraPosition;
Vec3f modelPos = new Vec3f(
MODEL_POS.set(
(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));
BEFORE_BUFFER_RENDER_EVENT_PARAM.update(renderEventParam, MODEL_POS);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, BEFORE_BUFFER_RENDER_EVENT_PARAM);
}
renderPass.setIndexBuffer(bufferWrapper.getIndexGpuBuffer(), VertexFormat.IndexType.INT);
renderPass.setVertexBuffer(0, bufferWrapper.vertexGpuBuffer); // vertex buffer can only be "0" lol
renderPassWrapper.setIndexBuffer(bufferWrapper.getIndexGpuBuffer());
renderPassWrapper.setVertexBuffer(bufferWrapper.vertexGpuBuffer);
if (!bufferWrapper.vertexGpuBuffer.isClosed())
{
renderPass.drawIndexed(
/*indexStart*/ 0,
/*firstIndex*/0,
/*indexCount*/bufferWrapper.indexCount,
/*instanceCount*/1);
renderPassWrapper.drawIndexed(bufferWrapper.indexCount);
}
}
}
@@ -353,7 +328,7 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
}
}
private String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
private String getRenderPassName() { return "distantHorizons:McLodRenderer"; }
private String getRenderPassName() { return "distantHorizons:TerrainRenderer"; }
//endregion
@@ -29,23 +29,26 @@ import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.BlazeVertexFormatBuilder;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.coreapi.ModInfo;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Copies the given color texture
@@ -57,13 +60,17 @@ import java.util.OptionalInt;
*/
public class BlazeDhApplyRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private RenderPipeline pipeline;
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("baseFragUniformBlock");
protected GpuBuffer vboGpuBuffer;
protected final String name;
@@ -92,7 +99,7 @@ public class BlazeDhApplyRenderer
*/
private final String[] uniformNames;
/** will be an empty array if unneeded */
private final GpuBuffer[] uniformBuffers;
private final BlazeUniformBufferWrapper[] uniformBufferWrappers;
@@ -128,7 +135,7 @@ public class BlazeDhApplyRenderer
this.fragmentShaderPath = fragmentShaderPath;
this.uniformNames = uniformNames;
this.uniformBuffers = new GpuBuffer[this.uniformNames.length];
this.uniformBufferWrappers = new BlazeUniformBufferWrapper[this.uniformNames.length];
}
private void tryInit(
@@ -179,10 +186,12 @@ public class BlazeDhApplyRenderer
pipelineBuilder.withUniformBuffer(uniformName);
}
pipelineBuilder.withUniformBuffer("baseFragUniformBlock");
pipelineBuilder.withSampler("uSourceColorTexture");
pipelineBuilder.withSampler("uSourceDepthTexture");
VertexFormat vertexFormat = VertexFormat.builder()
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
.build();
pipelineBuilder.withVertexFormat(vertexFormat);
@@ -191,7 +200,6 @@ public class BlazeDhApplyRenderer
this.pipeline = pipelineBuilder.build();
}
//endregion
@@ -201,7 +209,7 @@ public class BlazeDhApplyRenderer
//========//
//region
public void setUniform(String uniformName, GpuBuffer uniformBuffer)
public void setUniform(String uniformName, BlazeUniformBufferWrapper uniformBufferWrapper)
{
// the uniform array should be short enough (less than 10 items)
// where a sequential search should be plenty fast
@@ -210,7 +218,7 @@ public class BlazeDhApplyRenderer
String nameAtIndex = this.uniformNames[i];
if (nameAtIndex.equals(uniformName))
{
this.uniformBuffers[i] = uniformBuffer;
this.uniformBufferWrappers[i] = uniformBufferWrapper;
break;
}
}
@@ -225,32 +233,38 @@ public class BlazeDhApplyRenderer
this.dummyDepthTextureWrapper.tryCreateOrResize();
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this.fragUniformBufferWrapper
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
.finishAndUpload();
;
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getIdentifierName,
this.destinationColorTextureViewWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.dummyDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
this.destinationColorTextureViewWrapper,
this.dummyDepthTextureWrapper))
{
renderPass.bindTexture("uSourceColorTexture", this.sourceColorTextureViewWrapper.textureView, this.sourceColorTextureViewWrapper.textureSampler);
renderPass.bindTexture("uSourceDepthTexture", this.sourceDepthTextureViewWrapper.textureView, this.sourceDepthTextureViewWrapper.textureSampler);
renderPassWrapper.bindTexture("uSourceColorTexture", this.sourceColorTextureViewWrapper);
renderPassWrapper.bindTexture("uSourceDepthTexture", this.sourceDepthTextureViewWrapper);
for (int i = 0; i < this.uniformNames.length; i++)
{
String uniformName = this.uniformNames[i];
GpuBuffer uniformBuffer = this.uniformBuffers[i];
BlazeUniformBufferWrapper uniformBuffer = this.uniformBufferWrappers[i];
if (uniformBuffer == null)
{
throw new IllegalStateException("Missing uniform ["+uniformName+"], please set the uniform before rendering.");
}
renderPass.setUniform(uniformName, uniformBuffer);
renderPassWrapper.setUniform(uniformName, uniformBuffer);
}
renderPass.setVertexBuffer(0, this.vboGpuBuffer);
renderPass.setPipeline(this.pipeline);
renderPassWrapper.setUniform("baseFragUniformBlock", this.fragUniformBufferWrapper);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.draw(4);
}
@@ -258,7 +272,7 @@ public class BlazeDhApplyRenderer
// so we can check if they're missing during next frame's rendering
if (ModInfo.IS_DEV_BUILD)
{
Arrays.fill(this.uniformBuffers, null);
Arrays.fill(this.uniformBufferWrappers, null);
}
}
@@ -28,19 +28,16 @@ import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.IDhBlazeTexture;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Blindly copies one texture into another.
*
@@ -103,7 +100,7 @@ public class BlazeDhCopyRenderer
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McCopyRenderer");
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("CopyRenderer");
}
@@ -117,48 +114,28 @@ public class BlazeDhCopyRenderer
//region
public void render(
BlazeTextureWrapper sourceColorTextureWrapper,
BlazeTextureViewWrapper destinationColorTextureWrapper)
{
this.render(
sourceColorTextureWrapper.textureView, sourceColorTextureWrapper.textureSampler,
destinationColorTextureWrapper.textureView);
}
public void render(
BlazeTextureWrapper sourceColorTextureWrapper,
BlazeTextureWrapper destinationColorTextureWrapper)
{
this.render(
sourceColorTextureWrapper.textureView, sourceColorTextureWrapper.textureSampler,
destinationColorTextureWrapper.textureView);
}
private void render(
GpuTextureView sourceTextureView,
GpuSampler sourceTextureSampler,
GpuTextureView destinationTextureView)
IDhBlazeTexture sourceColorTextureWrapper,
IDhBlazeTexture destinationColorTextureWrapper)
{
this.tryInit();
this.dummyDepthTextureWrapper.tryCreateOrResize();
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
destinationTextureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.dummyDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
destinationColorTextureWrapper,
this.dummyDepthTextureWrapper))
{
renderPass.bindTexture("uCopyTexture", sourceTextureView, sourceTextureSampler);
renderPassWrapper.bindTexture("uCopyTexture", sourceColorTextureWrapper);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.draw(4);
}
}
private String getRenderPassName() { return "distantHorizons:McCopyRenderer"; }
private String getRenderPassName() { return "distantHorizons:CopyRenderer"; }
//endregion
@@ -25,33 +25,28 @@ public class BlazeDhFarFadeRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhCopyRenderer;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFarFadeRenderer;
import net.minecraft.client.Minecraft;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Fades out DH's far clip plane
@@ -62,13 +57,14 @@ public class BlazeDhFarFadeRenderer implements IDhFarFadeRenderer
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
public static final BlazeDhFarFadeRenderer INSTANCE = new BlazeDhFarFadeRenderer();
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("fragUniformBlock");
private GpuBuffer vboGpuBuffer;
@@ -123,7 +119,7 @@ public class BlazeDhFarFadeRenderer implements IDhFarFadeRenderer
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McFadeRenderer");
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("DhFarFadeRenderer");
}
//endregion
@@ -151,18 +147,11 @@ public class BlazeDhFarFadeRenderer implements IDhFarFadeRenderer
// textures
this.dhFadeColorTextureWrapper.tryCreateOrResize();
this.mcColorTextureViewWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getColorTexture());
this.mcColorTextureViewWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture());
this.dhFadeDepthTextureWrapper.tryCreateOrResize();
{
int uniformBufferSize = new Std140SizeCalculator()
.putFloat() // uStartFadeBlockDistance
.putFloat() // uEndFadeBlockDistance
.putMat4f() // uDhInvMvmProj
.get();
// create data //
float dhFarClipDistance = RenderUtil.getFarClipPlaneDistanceInBlocks();
@@ -170,30 +159,14 @@ public class BlazeDhFarFadeRenderer implements IDhFarFadeRenderer
float fadeEndDistance = dhFarClipDistance * 0.9f;
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(renderParams.mcProjectionMatrix);
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(renderParams.mcModelViewMatrix);
Mat4f inverseDhMvmProjMatrix = new Mat4f(dhProjectionMatrix);
inverseDhMvmProjMatrix.multiply(dhModelViewMatrix);
inverseDhMvmProjMatrix.invert();
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
fragUniformBufferWrapper
.putFloat(fadeStartDistance) // uStartFadeBlockDistance
.putFloat(fadeEndDistance) // uEndFadeBlockDistance
.putMat4f(inverseDhMvmProjMatrix.createJomlMatrix()) // uDhInvMvmProj
.get()
.putMat4f(renderParams.dhInverseMvmProjectionMatrix) // uDhInvMvmProj
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
.finishAndUpload()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
@@ -204,29 +177,27 @@ public class BlazeDhFarFadeRenderer implements IDhFarFadeRenderer
private void renderFadeToTexture()
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
this.dhFadeColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.dhFadeDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
this.dhFadeColorTextureWrapper,
this.dhFadeDepthTextureWrapper))
{
// MC texture
renderPass.bindTexture("uMcColorTexture", this.mcColorTextureViewWrapper.textureView, this.mcColorTextureViewWrapper.textureSampler);
renderPassWrapper.bindTexture("uMcColorTexture", this.mcColorTextureViewWrapper);
// DH textures
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
renderPass.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureSampler);
renderPassWrapper.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper);
renderPassWrapper.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper);
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
renderPassWrapper.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
renderPassWrapper.draw(4);
}
}
private String getRenderPassName() { return "distantHorizons:McFadeRenderer"; }
private String getRenderPassName() { return "distantHorizons:DhFarFadeRenderer"; }
//endregion
@@ -23,44 +23,44 @@ package com.seibel.distanthorizons.common.render.blaze.postProcessing;
public class BlazeDhFogRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DestFactor;
import com.mojang.blaze3d.platform.SourceFactor;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogColorMode;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiFogRenderParam;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFogRenderer;
import java.awt.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
#if MC_VER <= MC_26_1_2
import com.mojang.blaze3d.platform.DestFactor;
import com.mojang.blaze3d.platform.SourceFactor;
#else
import com.mojang.blaze3d.platform.BlendFactor;
#endif
/**
* Renders fog onto the LODs.
@@ -71,6 +71,7 @@ public class BlazeDhFogRenderer implements IDhFogRenderer
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
@@ -83,7 +84,7 @@ public class BlazeDhFogRenderer implements IDhFogRenderer
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("dh_fog_frag_uniform");
private GpuBuffer vboGpuBuffer;
@@ -109,11 +110,16 @@ public class BlazeDhFogRenderer implements IDhFogRenderer
this.init = true;
BlendFunction blendFunc;
#if MC_VER <= MC_26_1_2
blendFunc = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA);
#else
blendFunc = new BlendFunction(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA, BlendFactor.ONE, BlendFactor.ONE_MINUS_SRC_ALPHA);
#endif
this.applyRenderer = new BlazeDhApplyRenderer(
"fog_apply_to_dh",
new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA),
blendFunc,
"apply/blaze/vert", "apply/blaze/frag"
);
@@ -140,7 +146,7 @@ public class BlazeDhFogRenderer implements IDhFogRenderer
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McFogRenderer");
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("FogRenderer");
}
//endregion
@@ -153,7 +159,7 @@ public class BlazeDhFogRenderer implements IDhFogRenderer
//region
@Override
public void render(RenderParams renderParams)
public void render(RenderParams renderParams, DhApiFogRenderParam fogRenderParams)
{
this.tryInit();
@@ -170,144 +176,68 @@ public class BlazeDhFogRenderer implements IDhFogRenderer
this.fogDepthTextureWrapper.tryCreateOrResize();
{
int uniformBufferSize = new Std140SizeCalculator()
// fog uniforms
.putVec4() // uFogColor
.putFloat() //uFogScale
.putFloat() //uFogVerticalScale
// only used for debugging
.putInt() //uFogDebugMode // 1 = render everything with fog color // 7 = use debug rendering
.putInt() //uFogFalloffType
// fog config
.putFloat() // uFarFogStart
.putFloat() // uFarFogLength
.putFloat() // uFarFogMin
.putFloat() // uFarFogRange
.putFloat() // uFarFogDensity
// height fog config
.putFloat() // uHeightFogStart
.putFloat() // uHeightFogLength
.putFloat() // uHeightFogMin
.putFloat() // uHeightFogRange
.putFloat() // uHeightFogDensity
// ??
.putInt() // uHeightFogEnabled
.putInt() // uHeightFogFalloffType
.putInt() // uHeightBasedOnCamera
.putFloat() // uHeightFogBaseHeight
.putInt() // uHeightFogAppliesUp
.putInt() // uHeightFogAppliesDown
.putInt() // uUseSphericalFog
.putInt() // uHeightFogMixingMode
.putFloat() // uCameraBlockYPos
.putMat4f() // uInvMvmProj
.get();
// create data //
int lodDrawDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH;
Mat4f inverseMvmProjMatrix = new Mat4f(renderParams.dhMvmProjMatrix);
inverseMvmProjMatrix.invert();
if (renderParams.dhMvmProjMatrix == null)
{
return;
}
Color fogColor = this.getFogColor(renderParams.partialTicks);
// fog config
float farFogStart = Config.Client.Advanced.Graphics.Fog.farFogStart.get();
float farFogEnd = Config.Client.Advanced.Graphics.Fog.farFogEnd.get();
float farFogMin = Config.Client.Advanced.Graphics.Fog.farFogMin.get();
float farFogMax = Config.Client.Advanced.Graphics.Fog.farFogMax.get();
float farFogDensity = Config.Client.Advanced.Graphics.Fog.farFogDensity.get();
// override fog if underwater
if (MC_RENDER.isFogStateSpecial())
{
// hide everything behind fog
farFogStart = 0.0f;
farFogEnd = 0.0f;
}
// height config
EDhApiHeightFogMixMode heightFogMixingMode = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMixMode.get();
boolean heightFogEnabled = heightFogMixingMode != EDhApiHeightFogMixMode.SPHERICAL && heightFogMixingMode != EDhApiHeightFogMixMode.CYLINDRICAL;
EDhApiHeightFogMixMode heightFogMixingMode = fogRenderParams.getHeightFogMixingMode();
boolean heightFogEnabled =
heightFogMixingMode != EDhApiHeightFogMixMode.SPHERICAL
&& heightFogMixingMode != EDhApiHeightFogMixMode.CYLINDRICAL;
boolean useSphericalFog = heightFogMixingMode == EDhApiHeightFogMixMode.SPHERICAL;
EDhApiHeightFogDirection heightFogCameraDirection = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDirection.get();
float heightFogStart = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogStart.get();
float heightFogEnd = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogEnd.get();
float heightFogMin = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMin.get();
float heightFogMax = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMax.get();
float heightFogDensity = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDensity.get();
Color fogColor = fogRenderParams.getFogColor();
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
this.fragUniformBufferWrapper
// fog uniforms
.putVec4(
.putVec4f(
fogColor.getRed() / 255.0f,
fogColor.getGreen() / 255.0f,
fogColor.getBlue() / 255.0f,
fogColor.getAlpha() / 255.0f) // uFogColor
.putFloat(1.f / lodDrawDistance) //uFogScale
.putFloat(1.f / MC.getWrappedClientLevel().getMaxHeight()) //uFogVerticalScale
// only used for debugging
.putInt(0) //uFogDebugMode // 1 = render everything with fog color // 7 = use debug rendering
.putInt(Config.Client.Advanced.Graphics.Fog.farFogFalloff.get().value) //uFogFalloffType
.putInt(0) //uFogDebugMode // 0 = normal // 1 = render everything with fog color // 7 = use debug rendering
.putInt(fogRenderParams.getFarFogFalloff().value) //uFogFalloffType
// fog config
.putFloat(farFogStart) // uFarFogStart
.putFloat(farFogEnd - farFogStart) // uFarFogLength
.putFloat(farFogMin) // uFarFogMin
.putFloat(farFogMax - farFogMin) // uFarFogRange
.putFloat(farFogDensity) // uFarFogDensity
.putFloat(fogRenderParams.getFarFogStartPercent()) // uFarFogStart
.putFloat(fogRenderParams.getFarFogEndPercent() - fogRenderParams.getFarFogStartPercent()) // uFarFogLength
.putFloat(fogRenderParams.getFarFogMinThickness()) // uFarFogMin
.putFloat(fogRenderParams.getFarFogMaxThickness() - fogRenderParams.getFarFogMinThickness()) // uFarFogRange
.putFloat(fogRenderParams.getFarFogDensity()) // uFarFogDensity
// height fog config
.putFloat(heightFogStart) // uHeightFogStart
.putFloat(heightFogEnd - heightFogStart) // uHeightFogLength
.putFloat(heightFogMin) // uHeightFogMin
.putFloat(heightFogMax - heightFogMin) // uHeightFogRange
.putFloat(heightFogDensity) // uHeightFogDensity
.putFloat(fogRenderParams.getHeightFogStartPercent()) // uHeightFogStart
.putFloat(fogRenderParams.getHeightFogEndPercent() - fogRenderParams.getHeightFogStartPercent()) // uHeightFogLength
.putFloat(fogRenderParams.getHeightFogMinThickness()) // uHeightFogMin
.putFloat(fogRenderParams.getHeightFogMaxThickness() - fogRenderParams.getHeightFogMinThickness()) // uHeightFogRange
.putFloat(fogRenderParams.getHeightFogDensity()) // uHeightFogDensity
// ??
.putInt(heightFogEnabled ? 1 : 0) // uHeightFogEnabled
.putInt(Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogFalloff.get().value) // uHeightFogFalloffType
.putInt(heightFogCameraDirection.basedOnCamera ? 1 : 0) // uHeightBasedOnCamera
.putFloat(Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogBaseHeight.get()) // uHeightFogBaseHeight
.putInt(heightFogCameraDirection.fogAppliesUp ? 1 : 0) // uHeightFogAppliesUp
.putInt(heightFogCameraDirection.fogAppliesDown ? 1 : 0) // uHeightFogAppliesDown
.putInt(fogRenderParams.getHeightFogFalloff().value) // uHeightFogFalloffType
.putInt(fogRenderParams.getHeightFogDirection().basedOnCamera ? 1 : 0) // uHeightBasedOnCamera
.putFloat(fogRenderParams.getHeightFogBaseHeight()) // uHeightFogBaseHeight
.putInt(fogRenderParams.getHeightFogDirection().fogAppliesUp ? 1 : 0) // uHeightFogAppliesUp
.putInt(fogRenderParams.getHeightFogDirection().fogAppliesDown ? 1 : 0) // uHeightFogAppliesDown
.putInt(useSphericalFog ? 1 : 0) // uUseSphericalFog
.putInt(heightFogMixingMode.value) // uHeightFogMixingMode
.putFloat((float)MC_RENDER.getCameraExactPosition().y) // uCameraBlockYPos
.putMat4f(inverseMvmProjMatrix.createJomlMatrix()) // uInvMvmProj
.putMat4f(inverseMvmProjMatrix) // uInvMvmProj
.get()
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
.finishAndUpload()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
@@ -316,42 +246,26 @@ public class BlazeDhFogRenderer implements IDhFogRenderer
}
private Color getFogColor(float partialTicks)
{
Color fogColor;
if (Config.Client.Advanced.Graphics.Fog.colorMode.get() == EDhApiFogColorMode.USE_SKY_COLOR)
{
fogColor = MC_RENDER.getSkyColor();
}
else
{
fogColor = MC_RENDER.getFogColor(partialTicks);
}
return fogColor;
}
private void renderFogToTexture()
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
this.fogColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.fogDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
this.fogColorTextureWrapper,
this.fogDepthTextureWrapper))
{
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
renderPassWrapper.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper);
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPassWrapper.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
renderPassWrapper.draw(/*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:McFogRenderer"; }
private String getRenderPassName() { return "distantHorizons:FogRenderer"; }
//endregion
@@ -23,38 +23,38 @@ package com.seibel.distanthorizons.common.render.blaze.postProcessing;
public class BlazeDhSsaoRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DestFactor;
import com.mojang.blaze3d.platform.SourceFactor;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhSsaoRenderer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
#if MC_VER <= MC_26_1_2
import com.mojang.blaze3d.platform.DestFactor;
import com.mojang.blaze3d.platform.SourceFactor;
#else
import com.mojang.blaze3d.platform.BlendFactor;
#endif
/** Renders SSAO to the DH LODs. */
public class BlazeDhSsaoRenderer implements IDhSsaoRenderer
@@ -62,6 +62,7 @@ public class BlazeDhSsaoRenderer implements IDhSsaoRenderer
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
@@ -74,8 +75,8 @@ public class BlazeDhSsaoRenderer implements IDhSsaoRenderer
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private GpuBuffer applyFragUniformBuffer;
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("fragUniformBlock");
private final BlazeUniformBufferWrapper applyFragUniformBufferWrapper = new BlazeUniformBufferWrapper("applyFragUniformBlock");
private GpuBuffer vboGpuBuffer;
@@ -101,9 +102,17 @@ public class BlazeDhSsaoRenderer implements IDhSsaoRenderer
this.init = true;
BlendFunction blendFunc;
#if MC_VER <= MC_26_1_2
blendFunc = new BlendFunction(SourceFactor.ZERO, DestFactor.SRC_ALPHA, SourceFactor.ZERO, DestFactor.ONE);
#else
blendFunc = new BlendFunction(BlendFactor.ZERO, BlendFactor.SRC_ALPHA, BlendFactor.ZERO, BlendFactor.ONE);
#endif
this.applyRenderer = new BlazeDhApplyRenderer(
"ssao_apply_to_dh",
new BlendFunction(SourceFactor.ZERO, DestFactor.SRC_ALPHA, SourceFactor.ZERO, DestFactor.ONE),
blendFunc,
"apply/blaze/vert", "ssao/blaze/apply",
/*uniforms*/ new String[] { "applyFragUniformBlock" }
);
@@ -163,32 +172,14 @@ public class BlazeDhSsaoRenderer implements IDhSsaoRenderer
// frag uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putInt() // uSampleCount\
.putFloat() // uRadius
.putFloat() // uStrength
.putFloat() // uMinLight
.putFloat() // uBias
.putFloat() // uFadeDistanceInBlocks
.putMat4f() // uInvProj
.putMat4f() // uProj
.get();
// create data //
Mat4f projMatrix = new Mat4f(renderParams.dhProjectionMatrix);
Mat4f invertedProjMatrix = new Mat4f(renderParams.dhProjectionMatrix);
invertedProjMatrix.invert();
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
this.fragUniformBufferWrapper
.putInt(6) // uSampleCount
.putFloat(4.0f) // uRadius
@@ -197,27 +188,16 @@ public class BlazeDhSsaoRenderer implements IDhSsaoRenderer
.putFloat(0.02f) // uBias
.putFloat(1_600.0f) // uFadeDistanceInBlocks
.putMat4f(invertedProjMatrix.createJomlMatrix())
.putMat4f(projMatrix.createJomlMatrix())
.get()
.putMat4f(invertedProjMatrix)
.putMat4f(projMatrix)
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
.finishAndUpload()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
// apply frag uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putVec2() // uViewSize
.putInt() // uBlurRadius
.putFloat() // uNearClipPlane
.putFloat() // uFarClipPlane
.get();
// create data //
float viewWidth = (float)MC_RENDER.getTargetFramebufferViewportWidth();
@@ -228,51 +208,41 @@ public class BlazeDhSsaoRenderer implements IDhSsaoRenderer
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putVec2(viewWidth, viewHeight) // uViewSize
this.applyFragUniformBufferWrapper
.putVec2f(viewWidth, viewHeight) // uViewSize
.putInt(2) // uBlurRadius
.putFloat(nearClipPlane) // uNearClipPlane
.putFloat(farClipPlane) // uFarClipPlane
.get()
.finishAndUpload()
;
this.applyFragUniformBuffer = BlazeUniformUtil.createBuffer("applyFragUniformBlock", uniformBufferSize, this.applyFragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.applyFragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
this.renderSsaoToTexture();
this.applyRenderer.setUniform("applyFragUniformBlock", this.applyFragUniformBuffer);
this.applyRenderer.setUniform("applyFragUniformBlock", this.applyFragUniformBufferWrapper);
this.applyRenderer.render(this.ssaoColorTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.texture);
}
private void renderSsaoToTexture()
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
this.ssaoColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.ssaoDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
this.ssaoColorTextureWrapper,
this.ssaoDepthTextureWrapper))
{
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
renderPassWrapper.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper);
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.draw(4);
}
}
private String getRenderPassName() { return "distantHorizons:McSsaoRenderer"; }
private String getRenderPassName() { return "distantHorizons:SsaoRenderer"; }
//endregion
@@ -25,40 +25,30 @@ public class BlazeVanillaFadeRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhCopyRenderer;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhVanillaFadeRenderer;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.Identifier;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Fades the vanilla chunks
@@ -69,16 +59,18 @@ public class BlazeVanillaFadeRenderer implements IDhVanillaFadeRenderer
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeVanillaFadeRenderer INSTANCE = new BlazeVanillaFadeRenderer();
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("fragUniformBlock");
private GpuBuffer vboGpuBuffer;
@@ -136,7 +128,7 @@ public class BlazeVanillaFadeRenderer implements IDhVanillaFadeRenderer
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McFadeRenderer");
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("VanillaFadeRenderer");
}
//endregion
@@ -164,21 +156,11 @@ public class BlazeVanillaFadeRenderer implements IDhVanillaFadeRenderer
this.fadeColorTextureWrapper.tryCreateOrResize();
this.fadeDepthTextureWrapper.tryCreateOrResize();
this.mcDepthTextureWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getDepthTexture());
this.mcColorTextureWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getColorTexture());
this.mcDepthTextureWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getDepthTexture());
this.mcColorTextureWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture());
{
int uniformBufferSize = new Std140SizeCalculator()
.putInt() // uOnlyRenderLods
.putFloat() // uStartFadeBlockDistance
.putFloat() // uEndFadeBlockDistance
.putFloat() // uMaxLevelHeight
.putMat4f() // uDhInvMvmProj
.putMat4f() // uMcInvMvmProj
.get();
// create data //
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
@@ -198,34 +180,24 @@ public class BlazeVanillaFadeRenderer implements IDhVanillaFadeRenderer
Mat4f inverseMcMvmProjMatrix = inverseMcModelViewProjectionMatrix;
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(renderParams.mcProjectionMatrix);
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(renderParams.mcModelViewMatrix);
Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(dhProjectionMatrix);
inverseDhModelViewProjectionMatrix.multiply(dhModelViewMatrix);
Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(renderParams.dhProjectionMatrix);
inverseDhModelViewProjectionMatrix.multiply(renderParams.dhModelViewMatrix);
inverseDhModelViewProjectionMatrix.invert();
Mat4f inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix;
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
this.fragUniformBufferWrapper
.putInt(Config.Client.Advanced.Debugging.lodOnlyMode.get() ? 1 : 0) // uOnlyRenderLods
.putFloat(fadeStartDistance) // uStartFadeBlockDistance
.putFloat(fadeEndDistance) // uEndFadeBlockDistance
.putFloat(renderParams.clientLevelWrapper.getMaxHeight()) // uMaxLevelHeight
.putMat4f(inverseDhMvmProjMatrix.createJomlMatrix()) // uDhInvMvmProj
.putMat4f(inverseMcMvmProjMatrix.createJomlMatrix()) // uMcInvMvmProj
.get()
.putMat4f(inverseDhMvmProjMatrix) // uDhInvMvmProj
.putMat4f(inverseMcMvmProjMatrix) // uMcInvMvmProj
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
.finishAndUpload()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
@@ -236,28 +208,26 @@ public class BlazeVanillaFadeRenderer implements IDhVanillaFadeRenderer
private void renderFadeToTexture()
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
this.fadeColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.fadeDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
this.fadeColorTextureWrapper,
this.fadeDepthTextureWrapper))
{
renderPass.bindTexture("uMcDepthTexture", this.mcDepthTextureWrapper.textureView, this.mcDepthTextureWrapper.textureSampler);
renderPass.bindTexture("uCombinedMcDhColorTexture", this.mcColorTextureWrapper.textureView, this.mcColorTextureWrapper.textureSampler);
renderPassWrapper.bindTexture("uMcDepthTexture", this.mcDepthTextureWrapper);
renderPassWrapper.bindTexture("uCombinedMcDhColorTexture", this.mcColorTextureWrapper);
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
renderPass.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureSampler);
renderPassWrapper.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper);
renderPassWrapper.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper);
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.draw(/*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:McFadeRenderer"; }
private String getRenderPassName() { return "distantHorizons:VanillaFadeRenderer"; }
//endregion
@@ -35,8 +35,11 @@ import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.BlazeVertexFormatBuilder;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
@@ -106,7 +109,7 @@ public class BlazeDhTestTriangleRenderer implements IDhTestTriangleRenderer
pipelineBuilder.withVertexShader("test/blaze/vert");
pipelineBuilder.withFragmentShader("test/blaze/frag");
VertexFormat vertexFormat = VertexFormat.builder()
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
.add("vColor", BlazeDhVertexFormatUtil.RGBA_FLOAT_COLOR)
.build();
@@ -164,19 +167,17 @@ public class BlazeDhTestTriangleRenderer implements IDhTestTriangleRenderer
{
this.tryInit();
this.mcColorTextureViewWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getColorTexture());
this.mcDepthTextureViewWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getDepthTexture());
this.mcColorTextureViewWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture());
this.mcDepthTextureViewWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getDepthTexture());
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
this.mcColorTextureViewWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.mcDepthTextureViewWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
this.mcColorTextureViewWrapper,
this.mcDepthTextureViewWrapper))
{
renderPass.setVertexBuffer(0, this.vboGpuBuffer);
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 3);
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.draw(3);
}
}
private String getRenderPassName() { return "distantHorizons:DhTestRenderer"; }
@@ -4,9 +4,9 @@ package com.seibel.distanthorizons.common.render.blaze.util;
public class BlazeDhVertexFormatUtil {}
#else
import com.mojang.blaze3d.vertex.VertexFormatElement;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
@@ -16,6 +16,11 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import org.jetbrains.annotations.NotNull;
#if MC_VER <= MC_26_1_2
#else
import com.mojang.blaze3d.GpuFormat;
#endif
/**
* @see LodQuadBuilder
*/
@@ -43,14 +48,14 @@ public class BlazeDhVertexFormatUtil
static
{
EDhApiRenderApi renderingApi = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
if (renderingApi == EDhApiRenderApi.AUTO)
EDhApiRenderingEngine renderingApi = Config.Client.Advanced.Graphics.Experimental.renderingEngine.get();
if (renderingApi == EDhApiRenderingEngine.AUTO)
{
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
renderingApi = versionConstants.getDefaultRenderingApi();
renderingApi = versionConstants.getDefaultRenderingEngine();
}
boolean register = (renderingApi == EDhApiRenderApi.BLAZE_3D);
boolean register = (renderingApi == EDhApiRenderingEngine.BLAZE_3D);
if (register)
{
LOGGER.debug("Attempting to register ["+VertexFormatElement.class.getSimpleName()+"]...");
@@ -70,7 +75,7 @@ public class BlazeDhVertexFormatUtil
IRIS_NORMAL = VertexFormatElement.register(/*id*/29, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/30, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, /*count*/ 3);
#else
#elif MC_VER <= MC_26_1_2
SCREEN_POS = VertexFormatElement.register(/*id*/22, /*index*/0, VertexFormatElement.Type.FLOAT, false, /*count*/ 2);
RGBA_FLOAT_COLOR = VertexFormatElement.register(/*id*/23, /*index*/0, VertexFormatElement.Type.FLOAT, false, /*count*/ 4);
@@ -83,6 +88,35 @@ public class BlazeDhVertexFormatUtil
IRIS_NORMAL = VertexFormatElement.register(/*id*/29, /*index*/0, VertexFormatElement.Type.BYTE, false, /*count*/ 1);
FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/30, /*index*/0, VertexFormatElement.Type.FLOAT, false, /*count*/ 3);
#elif MC_VER <= MC_26_1_2
SCREEN_POS = VertexFormatElement.register(/*id*/22, /*index*/0, GpuFormat.RG32_FLOAT); // 2 floats
RGBA_FLOAT_COLOR = VertexFormatElement.register(/*id*/23, /*index*/0, GpuFormat.RGBA32_FLOAT); // 4 floats
SHORT_XYZ_POS = VertexFormatElement.register(/*id*/24, /*index*/0, GpuFormat.RGB16_UINT); // 3 ushorts
BYTE_PAD = VertexFormatElement.register(/*id*/25, /*index*/0, GpuFormat.R8_UINT); // 1 byte
META = VertexFormatElement.register(/*id*/26, /*index*/0, GpuFormat.R16_UINT); // 1 ushort
RGBA_UBYTE_COLOR = VertexFormatElement.register(/*id*/27, /*index*/0, GpuFormat.RGBA8_UNORM); // 4 ubytes
IRIS_MATERIAL = VertexFormatElement.register(/*id*/28, /*index*/0, GpuFormat.R8_UINT); // 1 byte
IRIS_NORMAL = VertexFormatElement.register(/*id*/29, /*index*/0, GpuFormat.R8_UINT); // 1 byte
FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/30, /*index*/0, GpuFormat.RGB32_FLOAT); // 3 floats
#else
SCREEN_POS = new VertexFormatElement("Screen Pos", Float.BYTES * 2, GpuFormat.RG32_FLOAT);
RGBA_FLOAT_COLOR = new VertexFormatElement("RGBA Float Color", Float.BYTES * 4, GpuFormat.RGBA32_FLOAT);
SHORT_XYZ_POS = new VertexFormatElement("Short XYZ Pos", Short.BYTES * 3, GpuFormat.RGB16_UINT);
BYTE_PAD = new VertexFormatElement("Byte Pad", 1, GpuFormat.R8_UINT);
META = new VertexFormatElement("DH Meta", Short.BYTES, GpuFormat.R16_UINT);
RGBA_UBYTE_COLOR = new VertexFormatElement("Rgba Ubyte Color", 4, GpuFormat.RGBA8_UNORM);
IRIS_MATERIAL = new VertexFormatElement("Iris Material", 1, GpuFormat.R8_UINT);
IRIS_NORMAL = new VertexFormatElement("Iris Normal", 1, GpuFormat.R8_UINT);
FLOAT_XYZ_POS = new VertexFormatElement("Float XYZ Pos", Float.BYTES * 3, GpuFormat.RGB32_FLOAT);
#endif
}
catch (Exception e)
@@ -118,5 +152,7 @@ public class BlazeDhVertexFormatUtil
}
#endif
@@ -11,6 +11,7 @@ import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.wrappers.BlazeVertexFormatBuilder;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -67,7 +68,7 @@ public class BlazePostProcessUtil
public static VertexFormat createVertexFormat()
{
VertexFormat vertexFormat = VertexFormat.builder()
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
.build();
return vertexFormat;
@@ -0,0 +1,58 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers;
#if MC_VER <= MC_1_21_10
public class BlazeVertexFormatBuilder {}
#else
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.blaze3d.vertex.VertexFormatElement;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
public class BlazeVertexFormatBuilder
{
private final VertexFormat.Builder builder;
//=============//
// constructor //
//=============//
//region
public BlazeVertexFormatBuilder()
{
#if MC_VER <= MC_26_1_2
this.builder = VertexFormat.builder();
#else
this.builder = VertexFormat.builder(0);
#endif
}
//endregion
//==========//
// building //
//==========//
//region
public BlazeVertexFormatBuilder add(String name, VertexFormatElement element)
{
#if MC_VER <= MC_26_1_2
this.builder.add(name, element);
#else
this.builder.addAttribute(name, element.format());
#endif
return this;
}
public VertexFormat build() { return this.builder.build(); }
//endregion
}
#endif
@@ -0,0 +1,162 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers;
#if MC_VER <= MC_1_21_10
public class RenderPassWrapper {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.IDhBlazeTexture;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.function.Supplier;
#if MC_VER <= MC_26_1_2
#else
import com.mojang.blaze3d.IndexType;
#endif
public class RenderPassWrapper implements AutoCloseable
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private final RenderPass renderPass;
//=============//
// constructor //
//=============//
//region
public RenderPassWrapper(
final Supplier<String> nameGetterFunc,
final IDhBlazeTexture colorTexture,
final IDhBlazeTexture depthTexture)
{
#if MC_VER <= MC_26_1_2
this.renderPass = COMMAND_ENCODER.createRenderPass(
nameGetterFunc,
colorTexture.getTextureView(),
/*optionalClearColorAsInt*/ OptionalInt.empty(),
depthTexture.getTextureView(),
/*optionalDepthValueAsDouble*/ OptionalDouble.empty());
#else
this.renderPass = COMMAND_ENCODER.createRenderPass(
nameGetterFunc,
colorTexture.getTextureView(),
/*clearColor*/ Optional.empty(),
depthTexture.getTextureView(),
/*clearDepth*/ OptionalDouble.empty());
#endif
}
//endregion
//=======//
// setup //
//=======//
//region
public void bindTexture(
final String name,
final IDhBlazeTexture textureView)
{
this.renderPass.bindTexture(
name,
textureView.getTextureView(),
textureView.getTextureSampler());
}
public void setVertexBuffer(GpuBuffer buffer)
{
#if MC_VER <= MC_26_1_2
this.renderPass.setVertexBuffer(/*slot*/0, buffer);
#else
this.renderPass.setVertexBuffer(/*slot*/0, buffer.slice());
#endif
}
public void setIndexBuffer(GpuBuffer buffer)
{
#if MC_VER <= MC_26_1_2
this.renderPass.setIndexBuffer(buffer, VertexFormat.IndexType.INT);
#else
this.renderPass.setIndexBuffer(buffer, IndexType.INT);
#endif
}
public void setUniform(String uniformName, BlazeUniformBufferWrapper uniformBuffer) { this.renderPass.setUniform(uniformName, uniformBuffer.getGpuBuffer()); }
public void setPipeline(RenderPipeline pipeline) { this.renderPass.setPipeline(pipeline); }
//endregion
//===========//
// rendering //
//===========//
//region
public void draw(int vertexCount)
{
#if MC_VER <= MC_26_1_2
this.renderPass.draw(0, vertexCount);
#else
this.renderPass.draw(vertexCount, /*instanceCount*/1, /*firstVertex*/0, /*firstInstance*/0);
#endif
}
public void drawIndexed(int indexCount)
{
#if MC_VER <= MC_26_1_2
this.renderPass.drawIndexed(
/*indexStart*/ 0,
/*firstIndex*/0,
indexCount,
/*instanceCount*/1);
#else
this.renderPass.drawIndexed(
indexCount,
/*instanceCount*/1,
/*firstVertex*/0,
/*vertexOffset*/0,
/*firstInstance*/0);
#endif
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close() { this.renderPass.close(); }
//endregion
}
#endif
@@ -6,8 +6,7 @@ public class RenderPipelineBuilderWrapper {}
#else
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.pipeline.*;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.vertex.VertexFormat;
@@ -15,14 +14,17 @@ 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;
#elif MC_VER <= MC_26_1_2
import com.mojang.blaze3d.platform.CompareOp;
#else
import com.mojang.blaze3d.platform.CompareOp;
import com.mojang.blaze3d.GpuFormat;
import com.mojang.blaze3d.PrimitiveTopology;
#endif
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Optional;
public class RenderPipelineBuilderWrapper
@@ -130,15 +132,27 @@ public class RenderPipelineBuilderWrapper
return this;
}
private final ArrayList<String> samplerNames = new ArrayList<>();
public RenderPipelineBuilderWrapper withSampler(String name) throws IllegalArgumentException
{
#if MC_VER <= MC_26_1_2
this.blazePipelineBuilder.withSampler(name);
#else
samplerNames.add(name);
#endif
return this;
}
private final ArrayList<String> uniformBufferNames = new ArrayList<>();
public RenderPipelineBuilderWrapper withUniformBuffer(String name) throws IllegalArgumentException
{
#if MC_VER <= MC_26_1_2
this.blazePipelineBuilder.withUniform(name, UniformType.UNIFORM_BUFFER);
#else
uniformBufferNames.add(name);
#endif
return this;
}
@@ -243,18 +257,31 @@ public class RenderPipelineBuilderWrapper
case LESS:
compareOp = CompareOp.LESS_THAN;
break;
case GREATER:
compareOp = CompareOp.GREATER_THAN;
break;
default:
throw new UnsupportedOperationException("No depth test defined for type ["+this.depthTest+"].");
}
this.blazePipelineBuilder.withDepthStencilState(new DepthStencilState(compareOp, this.writeDepth));
#if MC_VER <= MC_26_1_2
this.blazePipelineBuilder.withColorTargetState(
new ColorTargetState(
Optional.ofNullable(this.blendFunction),
this.writeColor ? ColorTargetState.WRITE_ALL : ColorTargetState.WRITE_NONE
)
);
#else
this.blazePipelineBuilder.withColorTargetState(
new ColorTargetState(
Optional.ofNullable(this.blendFunction),
GpuFormat.RGBA8_UNORM,
this.writeColor ? ColorTargetState.WRITE_ALL : ColorTargetState.WRITE_NONE
)
);
#endif
#endif
}
@@ -262,6 +289,7 @@ public class RenderPipelineBuilderWrapper
// vertex format
{
#if MC_VER <= MC_26_1_2
VertexFormat.Mode blazeVertexMode;
switch (this.vertexMode)
{
@@ -280,8 +308,56 @@ public class RenderPipelineBuilderWrapper
}
this.blazePipelineBuilder.withVertexFormat(vertexFormat, blazeVertexMode);
#else
PrimitiveTopology primitiveTopology;
switch (this.vertexMode)
{
case TRIANGLES:
primitiveTopology = PrimitiveTopology.TRIANGLES;
break;
case TRIANGLE_FAN:
primitiveTopology = PrimitiveTopology.TRIANGLE_FAN;
break;
case LINES:
primitiveTopology = PrimitiveTopology.DEBUG_LINES;
break;
default:
throw new UnsupportedOperationException("No PrimitiveTopology defined for type ["+this.vertexMode+"].");
}
this.blazePipelineBuilder.withVertexBinding(0, vertexFormat);
this.blazePipelineBuilder.withPrimitiveTopology(primitiveTopology);
#endif
}
// uniform buffers
{
#if MC_VER <= MC_26_1_2
// handled before this point
#else
BindGroupLayout.Builder bindGroupBuilder = BindGroupLayout.builder();
for (String name : this.samplerNames)
{
bindGroupBuilder.withSampler(name);
}
for (String name : this.uniformBufferNames)
{
bindGroupBuilder.withUniform(name, UniformType.UNIFORM_BUFFER);
}
BindGroupLayout bindGroup = bindGroupBuilder.build();
this.blazePipelineBuilder.withBindGroupLayout(bindGroup);
#endif
}
return this.blazePipelineBuilder.build();
}
@@ -342,6 +418,7 @@ public class RenderPipelineBuilderWrapper
public enum EDhDepthTest
{
NONE,
GREATER,
LESS;
}
@@ -14,7 +14,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import java.util.OptionalDouble;
public class BlazeTextureViewWrapper
public class BlazeTextureViewWrapper implements IDhBlazeTexture
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
@@ -22,8 +22,11 @@ public class BlazeTextureViewWrapper
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public GpuTextureView textureView = null;
public GpuSampler textureSampler = null;
private GpuTextureView textureView = null;
public GpuTextureView getTextureView() { return this.textureView; }
private GpuSampler textureSampler = null;
public GpuSampler getTextureSampler() { return this.textureSampler; }
@@ -5,11 +5,6 @@ public class BlazeTextureWrapper {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -18,7 +13,19 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRen
import java.util.OptionalDouble;
public class BlazeTextureWrapper
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
#if MC_VER <= MC_26_1_2
#else
import com.mojang.blaze3d.GpuFormat;
import org.joml.Vector4f;
#endif
public class BlazeTextureWrapper implements IDhBlazeTexture
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
@@ -29,11 +36,20 @@ public class BlazeTextureWrapper
public final String name;
#if MC_VER <= MC_26_1_2
public final TextureFormat textureFormat;
#else
public final GpuFormat textureFormat;
#endif
public GpuTexture texture = null;
public GpuTextureView textureView = null;
public GpuSampler textureSampler = null;
private GpuTextureView textureView = null;
public GpuTextureView getTextureView() { return this.textureView; }
private GpuSampler textureSampler = null;
public GpuSampler getTextureSampler() { return this.textureSampler; }
private int width = -1;
private int height = -1;
@@ -45,10 +61,27 @@ public class BlazeTextureWrapper
//==============//
//region
public static BlazeTextureWrapper createDepth(String name) { return new BlazeTextureWrapper(name, TextureFormat.DEPTH32); }
public static BlazeTextureWrapper createColor(String name) { return new BlazeTextureWrapper(name, TextureFormat.RGBA8); }
public static BlazeTextureWrapper createDepth(String name)
{
#if MC_VER <= MC_26_1_2
return new BlazeTextureWrapper(name, TextureFormat.DEPTH32);
#else
return new BlazeTextureWrapper(name, GpuFormat.D32_FLOAT);
#endif
}
public static BlazeTextureWrapper createColor(String name)
{
#if MC_VER <= MC_26_1_2
return new BlazeTextureWrapper(name, TextureFormat.RGBA8);
#else
return new BlazeTextureWrapper(name, GpuFormat.RGBA8_UNORM);
#endif
}
private BlazeTextureWrapper(String name, TextureFormat textureFormat)
private BlazeTextureWrapper(
String name,
#if MC_VER <= MC_26_1_2 TextureFormat #else GpuFormat #endif textureFormat
)
{
this.name = name;
this.textureFormat = textureFormat;
@@ -116,11 +149,13 @@ public class BlazeTextureWrapper
| GpuTexture.USAGE_TEXTURE_BINDING
| GpuTexture.USAGE_COPY_SRC
| GpuTexture.USAGE_RENDER_ATTACHMENT;
this.texture = GPU_DEVICE.createTexture(this.name,
this.texture = GPU_DEVICE.createTexture(
this.name,
usage,
this.textureFormat,
viewWidth, viewHeight,
/*depthOrLayers*/ 1, /*mipLevels*/ 1
/*depthOrLayers*/ 1, /*mipLevels*/ 1
);
this.textureView = GPU_DEVICE.createTextureView(this.texture);
@@ -156,7 +191,18 @@ public class BlazeTextureWrapper
{
if (this.texture != null)
{
#if MC_VER <= MC_26_1_2
COMMAND_ENCODER.clearColorTexture(this.texture, clearArgbColor);
#else
Vector4f clearColor = new Vector4f(
// color values should be between 0.0 and 1.0
ColorUtil.getRed(clearArgbColor) / 255.0f,
ColorUtil.getGreen(clearArgbColor) / 255.0f,
ColorUtil.getBlue(clearArgbColor) / 255.0f,
ColorUtil.getAlpha(clearArgbColor) / 255.0f
);
COMMAND_ENCODER.clearColorTexture(this.texture, clearColor);
#endif
}
}
@@ -0,0 +1,17 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.texture;
#if MC_VER <= MC_1_21_10
public interface IDhBlazeTexture {}
#else
import com.mojang.blaze3d.textures.GpuSampler;
import com.mojang.blaze3d.textures.GpuTextureView;
public interface IDhBlazeTexture
{
GpuTextureView getTextureView();
GpuSampler getTextureSampler();
}
#endif
@@ -5,14 +5,10 @@ public class BlazeLodUniformBufferWrapper {}
#else
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
import java.nio.ByteBuffer;
public class BlazeLodUniformBufferWrapper extends BlazeUniformBufferWrapper implements ILodContainerUniformBufferWrapper
{
@@ -37,35 +33,22 @@ public class BlazeLodUniformBufferWrapper extends BlazeUniformBufferWrapper impl
//region
@Override
public void createUniformData(LodBufferContainer bufferContainer)
{
Vec3f modelOffset = new Vec3f(
(float) (bufferContainer.minCornerBlockPos.getX()),
(float) (bufferContainer.minCornerBlockPos.getY()),
(float) (bufferContainer.minCornerBlockPos.getZ()));
// upload data //
int uniformBufferSize = new Std140SizeCalculator()
.putVec3() // uModelOffset
.get();
ByteBuffer buffer = this.getOrCreateBuffer(uniformBufferSize);
Std140Builder.intoBuffer(buffer)
.putVec3(modelOffset.x, modelOffset.y, modelOffset.z) // uModelOffset
.get();
}
@Override
public void tryUpload()
public void tryUpload(LodBufferContainer bufferContainer)
{
if (this.uploaded)
{
return;
}
this.upload();
Vec3f modelOffset = new Vec3f(
(float) (bufferContainer.minCornerBlockPos.getX()),
(float) (bufferContainer.minCornerBlockPos.getY()),
(float) (bufferContainer.minCornerBlockPos.getZ()));
// upload data //
this
.putVec3f(modelOffset.x, modelOffset.y, modelOffset.z) // uModelOffset
.finishAndUpload();
this.uploaded = true;
}
@@ -7,17 +7,23 @@ public class BlazeUniformBufferWrapper {}
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IUniformBufferWrapper;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
public class BlazeUniformBufferWrapper implements IUniformBufferWrapper
public class BlazeUniformBufferWrapper implements AutoCloseable
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@@ -27,11 +33,22 @@ public class BlazeUniformBufferWrapper implements IUniformBufferWrapper
private final String name;
private int cpuBufferSize = 0;
private int gpuBufferSize = 0;
/** measured in bytes */
private int bufferSize = 0;
private ByteBuffer cpuBuffer = null;
public GpuBuffer gpuBuffer = null;
private GpuBuffer gpuBuffer = null;
public GpuBuffer getGpuBuffer() { return this.gpuBuffer; }
private GpuBufferSlice bufferSlice = null;
/** the element count the current CPU Buffer is sized for */
private int previousElementCount = 0;
/** how many elements are currently in flight (ie being added to the buffer right now) */
private int elementCount = 0;
/** used to resize the buffers dur first-time setup */
private final ArrayList<EUniformElement> uniformElementTypes = new ArrayList<>(0);
private Std140Builder uniformBufferBuilder = null;
@@ -46,63 +63,136 @@ public class BlazeUniformBufferWrapper implements IUniformBufferWrapper
//========//
// render //
//========//
//=================//
// element builder //
//=================//
//region
protected ByteBuffer getOrCreateBuffer(int size)
public BlazeUniformBufferWrapper putVec2f(float x, float y)
{
if (this.cpuBuffer == null
|| this.cpuBufferSize != size)
this.putElement(EUniformElement.VEC2f);
this.uniformBufferBuilder.putVec2(x,y);
return this;
}
public BlazeUniformBufferWrapper putVec3i(int x, int y, int z)
{
this.putElement(EUniformElement.VEC3i);
this.uniformBufferBuilder.putIVec3(x,y,z);
return this;
}
public BlazeUniformBufferWrapper putVec3f(float x, float y, float z)
{
this.putElement(EUniformElement.VEC3f);
this.uniformBufferBuilder.putVec3(x,y,z);
return this;
}
public BlazeUniformBufferWrapper putVec4f(float x, float y, float z, float w)
{
this.putElement(EUniformElement.VEC4f);
this.uniformBufferBuilder.putVec4(x,y,z,w);
return this;
}
public BlazeUniformBufferWrapper putMat4f(DhApiMat4f matrix)
{
this.putElement(EUniformElement.MAT4f);
this.uniformBufferBuilder.putMat4f(Mat4f.createJomlMatrix(matrix));
return this;
}
public BlazeUniformBufferWrapper putFloat(float f)
{
this.putElement(EUniformElement.FLOAT);
this.uniformBufferBuilder.putFloat(f);
return this;
}
public BlazeUniformBufferWrapper putInt(int i)
{
this.putElement(EUniformElement.INT);
this.uniformBufferBuilder.putInt(i);
return this;
}
private void putElement(EUniformElement elementTypeEnum)
{
this.uniformElementTypes.add(elementTypeEnum);
boolean createNewBuilder = (this.elementCount == 0);
this.elementCount++;
if (this.elementCount > this.previousElementCount)
{
this.cpuBuffer = ByteBuffer.allocateDirect(size);
this.cpuBuffer.order(ByteOrder.nativeOrder());
this.cpuBufferSize = size;
this.recreateCpuBuffer();
createNewBuilder = true;
}
return this.cpuBuffer;
if (createNewBuilder)
{
this.uniformBufferBuilder = Std140Builder.intoBuffer(this.cpuBuffer);
}
}
private void recreateCpuBuffer()
{
ByteBuffer oldBuffer = this.cpuBuffer;
int size = calcBufferSize(this.uniformElementTypes);
this.cpuBuffer = MemoryUtil.memAlloc(size);
this.cpuBuffer.order(ByteOrder.nativeOrder());
if (oldBuffer != null)
{
oldBuffer.position(0);
this.cpuBuffer.put(oldBuffer);
MemoryUtil.memFree(oldBuffer);
}
this.bufferSize = size;
this.previousElementCount = this.elementCount;
}
private static int calcBufferSize(ArrayList<EUniformElement> uniformElements)
{
Std140SizeCalculator calculator = new Std140SizeCalculator();
for (int i = 0; i < uniformElements.size(); i++)
{
EUniformElement element = uniformElements.get(i);
switch (element)
{
case VEC2f -> calculator.putVec2();
case VEC3i -> calculator.putIVec3();
case VEC3f -> calculator.putVec3();
case VEC4f -> calculator.putVec4();
case MAT4f -> calculator.putMat4f();
case INT -> calculator.putInt();
case FLOAT -> calculator.putFloat();
default -> throw new UnsupportedOperationException("No definition for element type ["+element.name()+"]");
}
}
return calculator.get();
}
@Override
public void upload() throws IllegalStateException
public void finishAndUpload()
{
if (this.cpuBuffer == null)
// re-create the GPU buffer if needed
GpuBuffer oldGpuBuffer = this.gpuBuffer;
this.gpuBuffer = BlazeUniformUtil.createBuffer(this.name, this.bufferSize, this.gpuBuffer);
boolean createNewBufferSlice = (this.bufferSlice == null || this.gpuBuffer != oldGpuBuffer);
if (createNewBufferSlice)
{
throw new IllegalStateException("Upload called before buffer was created");
this.bufferSlice = new GpuBufferSlice(this.gpuBuffer, 0, this.bufferSize);
}
if (this.gpuBuffer == null
|| this.gpuBufferSize != this.cpuBufferSize)
{
if (this.gpuBuffer != null)
{
this.gpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX
| GpuBuffer.USAGE_UNIFORM;
this.gpuBuffer = GPU_DEVICE.createBuffer(this::getBufferName, usage, this.cpuBufferSize);
this.gpuBufferSize = this.cpuBufferSize;
}
// upload to GPU
this.cpuBuffer.position(0);
COMMAND_ENCODER.writeToBuffer(this.bufferSlice, this.cpuBuffer);
int byteSize = (this.cpuBuffer.limit() - this.cpuBuffer.position());
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.gpuBuffer, /*offset*/0, byteSize);
if (!bufferSlice.buffer().isClosed())
{
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.cpuBuffer);
}
else
{
LOGGER.warn("Uploading to buffer ["+this.name+"] failed due to already being closed");
}
// clear the element tracking for next time
this.elementCount = 0;
this.uniformElementTypes.clear();
this.uniformBufferBuilder = null;
}
private String getBufferName() { return this.name; }
//endregion
@@ -120,11 +210,35 @@ public class BlazeUniformBufferWrapper implements IUniformBufferWrapper
{
this.gpuBuffer.close();
}
if (this.cpuBuffer != null)
{
MemoryUtil.memFree(this.cpuBuffer);
}
}
//endregion
//================//
// helper classes //
//================//
//region
private enum EUniformElement
{
VEC2f,
VEC3f,
VEC3i,
VEC4f,
MAT4f,
INT,
FLOAT,
}
//endregion
}
#endif
@@ -10,7 +10,6 @@ import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.common.render.openGl.glObject.GlDhFramebuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.texture.*;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.apply.GlDhApplyShader;
import com.seibel.distanthorizons.common.render.openGl.terrain.GlDhTerrainShaderProgram;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config;
@@ -22,7 +21,6 @@ import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
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.coreapi.DependencyInjection.ApiEventInjector;
@@ -1,5 +1,7 @@
package com.seibel.distanthorizons.common.render.openGl;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
import com.seibel.distanthorizons.common.render.openGl.generic.GlGenericObjectRenderer;
import com.seibel.distanthorizons.common.render.openGl.generic.GlGenericObjectVertexContainer;
import com.seibel.distanthorizons.common.render.openGl.glObject.GlDummyUniformData;
@@ -8,8 +10,8 @@ import com.seibel.distanthorizons.common.render.openGl.postProcessing.fade.GlDhF
import com.seibel.distanthorizons.common.render.openGl.postProcessing.fade.GlVanillaFadeRenderer;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.fog.GlDhFogRenderer;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.ssao.GlDhSSAORenderer;
import com.seibel.distanthorizons.common.render.openGl.terrain.GlDhTerrainShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.test.GlTestTriangleRenderer;
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
@@ -26,6 +28,16 @@ public class GlDhRenderApiDefinition extends AbstractDhRenderApiDefinition
public String getApiName() { return "OpenGL"; }
public EDhRenderDepth getRenderDepth()
{
// reversed Z shouldn't be supported on OpenGL due
// to that breaking Iris shaders
return EDhRenderDepth.FORWARD_Z;
}
public EDhApiRenderingApi getRenderApi() { return EDhApiRenderingApi.OPEN_GL; }
public boolean isNativeRenderer() { return true; }
//endregion
@@ -75,6 +75,7 @@ public class GlGenericObjectRenderer implements IDhGenericRenderer
private static final DhApiRenderableBoxGroupShading DEFAULT_SHADING = DhApiRenderableBoxGroupShading.getUnshaded();
private static final DhApiBeforeGenericObjectRenderEvent.EventParam EVENT_PARAM = new DhApiBeforeGenericObjectRenderEvent.EventParam();
/**
* Can be used to troubleshoot the renderer.
@@ -418,7 +419,7 @@ public class GlGenericObjectRenderer implements IDhGenericRenderer
this.init();
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam.apiCopy);
boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get();
@@ -482,7 +483,8 @@ public class GlGenericObjectRenderer implements IDhGenericRenderer
}
// allow API users to cancel this object's rendering
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
EVENT_PARAM.update(renderEventParam, boxGroup);
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, EVENT_PARAM);
if (cancelRendering)
{
continue;
@@ -529,7 +531,7 @@ public class GlGenericObjectRenderer implements IDhGenericRenderer
profiler.popPush("cleanup");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam.apiCopy);
if (renderWireframe)
{
@@ -748,4 +750,27 @@ public class GlGenericObjectRenderer implements IDhGenericRenderer
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
if (this.boxVertexBuffer != null)
{
this.boxVertexBuffer.close();
}
if (this.boxIndexBuffer != null)
{
this.boxIndexBuffer.close();
}
}
//endregion
}
@@ -21,9 +21,9 @@ package com.seibel.distanthorizons.common.render.openGl.glObject;
import com.seibel.distanthorizons.api.enums.config.EDhApiGLErrorHandlingMode;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.api.enums.config.EDhApiLoggerLevel;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
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.jar.EPlatform;
@@ -32,6 +32,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.coreapi.ModInfo;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL;
@@ -51,6 +52,9 @@ import java.util.concurrent.ConcurrentHashMap;
public class GLProxy
{
private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
public static final DhLogger LOGGER;
static
@@ -126,13 +130,22 @@ public class GLProxy
private GLProxy() throws IllegalStateException
{
if (RENDER_API_DEF.getRenderApi() != EDhApiRenderingApi.OPEN_GL)
{
throw new IllegalStateException("[" + GLProxy.class.getSimpleName() + "] was created with the wrong Rendering API ["+RENDER_API_DEF.getRenderApi()+"]!");
}
// this must be created on minecraft's render context to work correctly
if (GLFW.glfwGetCurrentContext() == 0L)
{
throw new IllegalStateException(GLProxy.class.getSimpleName() + " was created outside the render thread!");
String message = "[" + GLProxy.class.getSimpleName() + "] was created outside the render thread!";
IllegalStateException exception = new IllegalStateException(message);
MC_CLIENT.crashMinecraft(message, exception);
throw exception;
}
LOGGER.info("Creating " + GLProxy.class.getSimpleName() + "... If this is the last message you see there must have been an OpenGL error.");
LOGGER.info("Creating [" + GLProxy.class.getSimpleName() + "]... If this is the last message you see there must have been an OpenGL error.");
LOGGER.info("Lod Render OpenGL version [" + GL32.glGetString(GL32.GL_VERSION) + "].");
@@ -97,7 +97,9 @@ public class GLState implements AutoCloseable
{
this.frameBufferTexture0 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
this.frameBufferTexture1 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
this.frameBufferDepthTexture = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
int depthType = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
this.frameBufferDepthTexture = (depthType == GL32.GL_TEXTURE) ? GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) : 0;
}
else
{
@@ -179,9 +181,21 @@ public class GLState implements AutoCloseable
// attempting to set textures on the default frame buffer (ID 0) will throw errors
if (frameBufferSet)
{
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.frameBufferTexture0, 0);
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_TEXTURE_2D, this.frameBufferTexture1, 0);
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_TEXTURE_2D, this.frameBufferDepthTexture, 0);
if (GL32.glIsTexture(this.frameBufferTexture0))
{
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.frameBufferTexture0, 0);
}
if (this.frameBufferTexture1 != 0 && GL32.glIsTexture(this.frameBufferTexture1))
{
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_TEXTURE_2D, this.frameBufferTexture1, 0);
}
if (GL32.glIsTexture(this.frameBufferDepthTexture))
{
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_TEXTURE_2D, this.frameBufferDepthTexture, 0);
}
}
GL32.glBindVertexArray(GL32.glIsVertexArray(this.vao) ? this.vao : 0);
@@ -9,9 +9,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodCont
*/
public class GlDummyUniformData implements ILodContainerUniformBufferWrapper
{
@Override public void createUniformData(LodBufferContainer bufferContainer) { }
@Override public void tryUpload() { }
@Override public void upload() { }
@Override public void tryUpload(LodBufferContainer bufferContainer) { }
@Override public void close() { }
}
@@ -21,14 +21,19 @@ package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLState;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.ThreadUtil;
import com.seibel.distanthorizons.core.util.objects.Pair;
import com.seibel.distanthorizons.core.util.objects.pooling.PhantomLoggingHelper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.coreapi.util.StringUtil;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL44;
@@ -36,9 +41,12 @@ import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.StampedLock;
public class GLBuffer implements AutoCloseable
{
@@ -50,26 +58,57 @@ public class GLBuffer implements AutoCloseable
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
// TODO move to a shared location that can be handled by both GL and Blaze3D buffers
/** if enabled the number of GC'ed buffers will be logged */
private static final boolean LOG_PHANTOM_RECOVERY = ModInfo.IS_DEV_BUILD;
/** If enabled buffers allocation/upload stacks will be logged when GC'ed. */
private static final boolean LOG_PHANTOM_ALLOCATION_STACKS = false; // disabled by default due to the increased GC load
public static final double BUFFER_EXPANSION_MULTIPLIER = 1.3;
public static final double BUFFER_SHRINK_TRIGGER = BUFFER_EXPANSION_MULTIPLIER * BUFFER_EXPANSION_MULTIPLIER;
/**
* On macOS the legacy OpenGL -> Metal bridge crashes with SIGBUS in
* {@code _platform_memmove} when {@code glBufferData} or {@code glBufferSubData}
* are called with a large ByteBuffer in one shot. To work around it, we split
* the upload into smaller sub-data calls that each fit comfortably inside the
* driver's internal staging path. <br>
* 256 KiB tuned empirically against macOS 26.5 — a 1 MiB chunk still
* tripped the same {@code _platform_memmove} crash inside
* {@code glBufferSubData_Exec}, but 256 KiB consistently survives.
*/
public static final int MAC_UPLOAD_CHUNK_BYTES = 256 * 1024;
/** Threshold above which the chunked path kicks in on macOS. */
public static final int MAC_UPLOAD_CHUNK_THRESHOLD = MAC_UPLOAD_CHUNK_BYTES;
/** the number of active buffers, can be used for debugging */
public static AtomicInteger bufferCount = new AtomicInteger(0);
private static final int PHANTOM_REF_CHECK_TIME_IN_MS = 5 * 1000;
private static final ConcurrentHashMap<PhantomReference<? extends GLBuffer>, Integer> PHANTOM_TO_BUFFER_ID = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<Integer, PhantomReference<? extends GLBuffer>> BUFFER_ID_TO_PHANTOM = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<Integer, String> BUFFER_ID_TO_ALLOCATION_STRING = new ConcurrentHashMap<>();
private static final ReferenceQueue<GLBuffer> PHANTOM_REFERENCE_QUEUE = new ReferenceQueue<>();
private static final ThreadPoolExecutor CLEANUP_THREAD = ThreadUtil.makeSingleDaemonThreadPool("GLBuffer Cleanup");
protected int id;
protected volatile int id = 0;
public final int getId() { return this.id; }
protected int size = 0;
public int getSize() { return this.size; }
protected boolean bufferStorage;
public final boolean isBufferStorage() { return this.bufferStorage; }
protected boolean isMapped = false;
/**
* Locking on the render thread isn't great, but is needed due to an inconsistent
* race condition where VBOs can be marked as deleted outside the render thread. <br><br>
*
* But, due to being a read-write lock the chance of freezing
* the render thread is very low
* and since this is a stamped lock, the optimistic read time is basically zero.
* (The optimistic lock time doesn't even appear in the profiler).
*/
public final StampedLock renderStampLock = new StampedLock();
//==============//
@@ -112,72 +151,119 @@ public class GLBuffer implements AutoCloseable
LodUtil.assertNotReach("Thread ["+Thread.currentThread()+"] tried to create a GLBuffer outside the MC render thread.");
}
// destroy the old buffer if one is present
if (this.id != 0)
// lock to prevent the render thread from accessing the buffer's ID
// while we are removing it
long writeStamp = renderStampLock.writeLock();
try
{
destroyBufferIdNow(this.id);
final int oldId = this.id;
this.id = GLMC.glGenBuffers();
//LOGGER.info("created [" + newId + "].");
// destroy the old buffer
// after the new one has been created
// to hopefully prevent a rare race conditions where the old ID
// is still used somewhere
if (oldId != 0)
{
// this ID doesn't need to be tracked anymore
tryRemoveBufferIdFromPhantom(oldId);
destroyBufferIdNow(oldId, "destroyOldAndCreate");
}
this.bufferStorage = asBufferStorage;
bufferCount.getAndIncrement();
PhantomReference<GLBuffer> phantom = new PhantomReference<>(this, PHANTOM_REFERENCE_QUEUE);
PHANTOM_TO_BUFFER_ID.put(phantom, this.id);
BUFFER_ID_TO_PHANTOM.put(this.id, phantom);
this.updateAllocationStackTrace();
}
finally
{
renderStampLock.unlock(writeStamp);
}
this.id = GLMC.glGenBuffers();
this.bufferStorage = asBufferStorage;
bufferCount.getAndIncrement();
PhantomReference<GLBuffer> phantom = new PhantomReference<>(this, PHANTOM_REFERENCE_QUEUE);
PHANTOM_TO_BUFFER_ID.put(phantom, this.id);
BUFFER_ID_TO_PHANTOM.put(this.id, phantom);
}
protected void destroyAsync()
{
if (this.id == 0)
// lock to prevent the render thread from accessing the buffer's ID
// while we are removing it
long writeStamp = renderStampLock.writeLock();
try
{
// the buffer has already been closed
return;
if (this.id == 0)
{
// the buffer has already been closed
return;
}
final int idToDelete = this.id; // saving the ID to a separate variable is necessary so it can be captured by the lambda
// remove the phantom tracking now so the phantom doesn't have the chance to
// get garbage collected before the render thread task runs
// (this can happen if MC is running at extremely low framerates like 1 fps via mods)
tryRemoveBufferIdFromPhantom(idToDelete);
// mark the old data is invalid before deleting to prevent a rare race condition
// where the queued on render thread task runs before the ID is cleared
this.id = 0;
this.size = 0;
//LOGGER.info("async destroy [" + idToDelete + "].");
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer destroyAsync", () -> { destroyBufferIdNow(idToDelete, "destroyAsync"); });
}
finally
{
renderStampLock.unlock(writeStamp);
}
final int idToDelete = this.id; // saving the ID to a separate variable is necessary so it can be captured by the lambda
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer destroyAsync", () -> { destroyBufferIdNow(idToDelete); });
this.id = 0;
this.size = 0;
}
private static void destroyBufferIdNow(int id)
private static void destroyBufferIdNow(int id, String cause)
{
// only delete valid buffers
if (id == 0)
{
LOGGER.warn("Attempted to destroy a buffer with ID 0, VRAM memory leaks may occur.");
LOGGER.warn("Attempted to destroy a buffer with ID 0, VRAM memory leaks may occur, cause: ["+cause+"].");
return;
}
// remove and clear the phantom reference if present
if (BUFFER_ID_TO_PHANTOM.containsKey(id))
bufferCount.decrementAndGet();
GLMC.glDeleteBuffers(id);
if (Config.Client.Advanced.Debugging.logBufferGarbageCollection.get())
{
LOGGER.info("destroyed buffer [" + id + "], remaining: [" + BUFFER_ID_TO_PHANTOM.size() + "], cause: ["+cause+"].");
}
}
/** should be called before {@link GLBuffer#destroyBufferIdNow} */
private static void tryRemoveBufferIdFromPhantom(int id)
{
// will contain nothing if stack tracking isn't enabled
BUFFER_ID_TO_ALLOCATION_STRING.remove(id);
PhantomReference<? extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.remove(id);
if (phantom != null)
{
Reference<? extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.get(id);
// if we are manually closing this buffer, we don't want the phantom reference to accidentally close it again
// this can cause a race condition were we accidentally delete an in-use buffer and cause NVIDIA
// to throw an EXCEPTION_ACCESS_VIOLATION when we attempt to render it
phantom.clear();
PHANTOM_TO_BUFFER_ID.remove(phantom);
BUFFER_ID_TO_PHANTOM.remove(id);
}
bufferCount.decrementAndGet();
// destroy the buffer if it exists,
// the buffer may not exist if the destroy method is called twice
if (GL32.glIsBuffer(id))
{
GLMC.glDeleteBuffers(id);
if (Config.Client.Advanced.Debugging.logBufferGarbageCollection.get())
Integer phantomId = PHANTOM_TO_BUFFER_ID.remove(phantom);
if (phantomId == null)
{
LOGGER.info("destroyed buffer [" + id + "], remaining: [" + BUFFER_ID_TO_PHANTOM.size() + "]");
LOGGER.warn("No Phantom->ID binding stored for ID ["+id+"]");
}
}
else
{
LOGGER.warn("Unable to remove phantom GLBuffer with ID ["+id+"], buffer may have already been deleted.");
}
}
//endregion
@@ -263,8 +349,25 @@ public class GLBuffer implements AutoCloseable
LodUtil.assertTrue(!this.bufferStorage, "Buffer is bufferStorage but its trying to use bufferData upload method!");
int bbSize = bb.limit() - bb.position();
GL32.glBufferData(this.getBufferBindingTarget(), bb, bufferDataHint);
int target = this.getBufferBindingTarget();
if (shouldUploadToGpuInChunks(bbSize))
{
// Two-step path used on macOS to dodge the Apple OpenGL -> Metal
// memmove SIGBUS triggered by uploading a large ByteBuffer in one
// glBufferData call:
// 1) allocate-only with the size overload (no memcpy)
// 2) fill the buffer through chunked glBufferSubData calls
GL32.glBufferData(target, (long) bbSize, bufferDataHint);
subDataUploadInChunks(target, 0, bb, MAC_UPLOAD_CHUNK_BYTES);
}
else
{
GL32.glBufferData(target, bb, bufferDataHint);
}
this.size = bbSize;
this.updateAllocationStackTrace();
}
/** Requires the buffer to be bound */
protected void uploadSubData(ByteBuffer bb, int maxExpansionSize, int bufferDataHint)
@@ -272,14 +375,30 @@ public class GLBuffer implements AutoCloseable
LodUtil.assertTrue(!this.bufferStorage, "Buffer is bufferStorage but its trying to use subData upload method!");
int bbSize = bb.limit() - bb.position();
int target = this.getBufferBindingTarget();
if (this.size < bbSize || this.size > bbSize * BUFFER_SHRINK_TRIGGER)
{
int newSize = (int) (bbSize * BUFFER_EXPANSION_MULTIPLIER);
if (newSize > maxExpansionSize) newSize = maxExpansionSize;
GL32.glBufferData(this.getBufferBindingTarget(), newSize, bufferDataHint);
if (newSize > maxExpansionSize)
{
newSize = maxExpansionSize;
}
// allocate-only — no memcpy, safe on macOS regardless of size
GL32.glBufferData(target, (long) newSize, bufferDataHint);
this.size = newSize;
}
GL32.glBufferSubData(this.getBufferBindingTarget(), 0, bb);
if (shouldUploadToGpuInChunks(bbSize))
{
subDataUploadInChunks(target, 0, bb, MAC_UPLOAD_CHUNK_BYTES);
}
else
{
GL32.glBufferSubData(target, 0, bb);
}
this.updateAllocationStackTrace();
}
//endregion
@@ -321,7 +440,6 @@ public class GLBuffer implements AutoCloseable
{
// recreate if the buffer storage type changed
this.bind();
destroyBufferIdNow(this.id);
this.destroyOldAndCreate(uploadMethod.useBufferStorage);
this.bind();
}
@@ -338,6 +456,91 @@ public class GLBuffer implements AutoCloseable
}
}
/**
* macOS-only mitigation for the SIGBUS in
* {@code libsystem_platform.dylib _platform_memmove} that happens when the
* Apple OpenGL -> Metal translation layer copies a single large ByteBuffer
* out of LWJGL into driver memory. Splitting the copy into
* {@link #MAC_UPLOAD_CHUNK_BYTES} slices keeps every memmove inside a size
* the bridge handles reliably.
*/
private static boolean shouldUploadToGpuInChunks(int byteCount)
{
return EPlatform.get() == EPlatform.MACOS
&& byteCount > MAC_UPLOAD_CHUNK_THRESHOLD;
}
/**
* Uploads {@code bb} into the currently bound buffer at {@code baseOffset}
* using a sequence of {@link GL32#glBufferSubData(int, long, ByteBuffer)}
* calls of at most {@code chunkBytes} each. The buffer's position/limit are
* restored before returning.
*/
private static void subDataUploadInChunks(int target, int baseOffset, ByteBuffer bb, int chunkBytes)
{
final int origPos = bb.position();
final int origLimit = bb.limit();
try
{
final int total = origLimit - origPos;
int uploaded = 0;
while (uploaded < total)
{
int chunk = Math.min(chunkBytes, total - uploaded);
bb.position(origPos + uploaded);
bb.limit(origPos + uploaded + chunk);
GL32.glBufferSubData(target, (long) (baseOffset + uploaded), bb);
uploaded += chunk;
// Force the driver to drain its command queue between chunks
// so the OpenGL -> Metal bridge processes (and frees) each
// staging copy before the next sub-data call piles another
// memmove on top of it.
if (uploaded < total)
{
GL32.glFlush();
}
}
}
finally
{
bb.limit(origLimit);
bb.position(origPos);
}
}
/**
* used to help track down leaks where the buffer isn't properly closed
* Note: this probably needs extending to accept a stack trace from outside where it's being called
* since it's often called on the render thread in an un-helpful location.
*/
public void updateAllocationStackTrace()
{
if (LOG_PHANTOM_ALLOCATION_STACKS)
{
String stack;
RenderThreadTaskHandler.QueuedRunnable parentQueuedRunnable;
// if this is running on the render thread, try getting the render task's stack trace instead
// since it's a lot more helpful than wherever the render thread tasks themselves are being run from
if (RenderThreadTaskHandler.INSTANCE.isCurrentThread()
&& (parentQueuedRunnable = RenderThreadTaskHandler.INSTANCE.getCurrentlyRunningTask()) != null
&& parentQueuedRunnable.stackTrace != null)
{
// trim off the getStacktrace() and queueRunningOnRenderThread() methods
StackTraceElement[] trimmedElements = Arrays.copyOfRange(parentQueuedRunnable.stackTrace, 2, parentQueuedRunnable.stackTrace.length);
stack = StringUtil.join("\n", trimmedElements).intern();
}
else
{
// not running on the render thread, use the normal stack trace
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
stack = StringUtil.join("\n", stackTraceElements).intern();
}
BUFFER_ID_TO_ALLOCATION_STRING.put(this.id, stack);
}
}
//endregion
@@ -349,8 +552,13 @@ public class GLBuffer implements AutoCloseable
private static void runPhantomReferenceCleanupLoop()
{
// these arrays are stored here so they don't have to be re-allocated each loop
ArrayList<Pair<String, AtomicInteger>> allocationStackTraceCountPairList = new ArrayList<>();
while (true)
{
allocationStackTraceCountPairList.clear();
try
{
try
@@ -359,20 +567,53 @@ public class GLBuffer implements AutoCloseable
}
catch (InterruptedException ignore) { }
int collectedCount = 0;
Reference<? extends GLBuffer> phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
while (phantomRef != null)
{
// destroy the buffer if it hasn't been cleared yet
if (PHANTOM_TO_BUFFER_ID.containsKey(phantomRef))
Integer idRef = PHANTOM_TO_BUFFER_ID.remove((PhantomReference<? extends GLBuffer>)phantomRef); // cast to make IntelliJ happy
if (idRef != null)
{
int id = PHANTOM_TO_BUFFER_ID.get(phantomRef);
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer phantom destroy", () -> { destroyBufferIdNow(id); });
//LOGGER.warn("Buffer Phantom collected, ID: ["+id+"]");
BUFFER_ID_TO_PHANTOM.remove(idRef);
final int id = idRef;
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer phantom destroy", () -> { destroyBufferIdNow(id, "runPhantomReferenceCleanupLoop"); });
//LOGGER.info("Buffer Phantom collected, ID: ["+id+"]");
if (LOG_PHANTOM_ALLOCATION_STACKS) // stack trace shouldn't be null, but just in case
{
String stack = BUFFER_ID_TO_ALLOCATION_STRING.get(idRef);
PhantomLoggingHelper.putAndIncrementTrackingString(stack, allocationStackTraceCountPairList);
}
}
else
{
LOGGER.warn("Failed to find Buffer ID for phantom reference: ["+phantomRef+"]");
}
collectedCount++;
phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
}
if (LOG_PHANTOM_RECOVERY)
{
// we only want to log when something has been returned
if (collectedCount != 0)
{
LOGGER.warn("GLBuffer phantom recovered: ["+ F3Screen.NUMBER_FORMAT.format(collectedCount)+"].");
// log stack traces if present
if (LOG_PHANTOM_ALLOCATION_STACKS)
{
PhantomLoggingHelper.LogAllocationStackTracePairCounts(LOGGER, allocationStackTraceCountPairList);
}
}
}
}
catch (Exception e)
{
@@ -37,10 +37,11 @@ public class GLIndexBuffer extends GLBuffer
protected int glType = GL32.GL_UNSIGNED_INT;
public int getGlType() { return this.glType; }
public GLIndexBuffer(boolean isBufferStorage)
{
super(isBufferStorage);
}
public GLIndexBuffer(boolean isBufferStorage) { super(isBufferStorage); }
@Override
public void destroyAsync()
@@ -22,6 +22,7 @@ package com.seibel.distanthorizons.common.render.openGl.glObject.shader;
import java.awt.Color;
import java.nio.FloatBuffer;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3i;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryStack;
@@ -187,20 +188,44 @@ public class GlShaderProgram
/** Requires a bound ShaderProgram. */
public void setUniform(int location, DhApiVec3i value) { GL32.glUniform3i(location, value.x, value.y, value.z); }
/** @see GlShaderProgram#setUniform(int, Mat4f) */
/** @see GlShaderProgram#setUniform(int, DhApiMat4f) */
public void trySetUniform(int location, DhApiVec3i value) { if (location != -1) { this.setUniform(location, value); } }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, Mat4f value)
public void setUniform(int location, DhApiMat4f value)
{
try (MemoryStack stack = MemoryStack.stackPush())
{
FloatBuffer buffer = stack.mallocFloat(4 * 4);
value.store(buffer);
FloatBuffer buffer = stack.mallocFloat(16);
storeMatrixInBuffer(value, buffer);
GL32.glUniformMatrix4fv(location, false, buffer);
}
}
/** @see GlShaderProgram#setUniform(int, Mat4f) */
private static void storeMatrixInBuffer(DhApiMat4f matrix, FloatBuffer floatBuffer)
{
floatBuffer.put(bufferIndex(0, 0), matrix.m00);
floatBuffer.put(bufferIndex(0, 1), matrix.m01);
floatBuffer.put(bufferIndex(0, 2), matrix.m02);
floatBuffer.put(bufferIndex(0, 3), matrix.m03);
floatBuffer.put(bufferIndex(1, 0), matrix.m10);
floatBuffer.put(bufferIndex(1, 1), matrix.m11);
floatBuffer.put(bufferIndex(1, 2), matrix.m12);
floatBuffer.put(bufferIndex(1, 3), matrix.m13);
floatBuffer.put(bufferIndex(2, 0), matrix.m20);
floatBuffer.put(bufferIndex(2, 1), matrix.m21);
floatBuffer.put(bufferIndex(2, 2), matrix.m22);
floatBuffer.put(bufferIndex(2, 3), matrix.m23);
floatBuffer.put(bufferIndex(3, 0), matrix.m30);
floatBuffer.put(bufferIndex(3, 1), matrix.m31);
floatBuffer.put(bufferIndex(3, 2), matrix.m32);
floatBuffer.put(bufferIndex(3, 3), matrix.m33);
}
private static int bufferIndex(int xIndex, int zIndex) { return (zIndex * 4) + xIndex; }
/** @see GlShaderProgram#setUniform(int, DhApiMat4f) */
public void trySetUniform(int location, Mat4f value) { if (location != -1) { this.setUniform(location, value); } }
/**
@@ -132,7 +132,7 @@ public class GlDhApplyShader extends GlAbstractShaderRenderer
}
private void renderToMcTexture()
{
int targetColorTextureId = MC_RENDER.getColorTextureId();
int targetColorTextureId = MC_RENDER.getGlColorTextureId();
if (targetColorTextureId == -1)
{
return;
@@ -136,7 +136,7 @@ public class GlDhFarFadeRenderer implements IDhFarFadeRenderer
GlDhFarFadeShader.INSTANCE.frameBuffer = this.fadeFramebuffer;
GlDhFarFadeShader.INSTANCE.setProjectionMatrix(renderParams.mcModelViewMatrix, renderParams.mcProjectionMatrix);
GlDhFarFadeShader.INSTANCE.setProjectionMatrix(renderParams);
GlDhFarFadeShader.INSTANCE.render(renderParams);
GlDhFarFadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture;
@@ -42,7 +42,7 @@ public class GlDhFarFadeShader extends GlAbstractShaderRenderer
public int frameBuffer = -1;
private Mat4f inverseDhMvmProjMatrix;
private DhApiMat4f inverseDhMvmProjMatrix;
// Uniforms
@@ -110,15 +110,9 @@ public class GlDhFarFadeShader extends GlAbstractShaderRenderer
}
public void setProjectionMatrix(DhApiMat4f mcModelViewMatrix, DhApiMat4f mcProjectionMatrix)
public void setProjectionMatrix(RenderParams renderParams)
{
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(mcProjectionMatrix);
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(mcModelViewMatrix);
Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(dhProjectionMatrix);
inverseDhModelViewProjectionMatrix.multiply(dhModelViewMatrix);
inverseDhModelViewProjectionMatrix.invert();
this.inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix;
this.inverseDhMvmProjMatrix = renderParams.dhInverseMvmProjectionMatrix;
}
@@ -153,7 +147,7 @@ public class GlDhFarFadeShader extends GlAbstractShaderRenderer
GL32.glUniform1i(this.uDhDepthTexture, 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
GLMC.glBindTexture(MC_RENDER.getColorTextureId());
GLMC.glBindTexture(MC_RENDER.getGlColorTextureId());
GL32.glUniform1i(this.uMcColorTexture, 1);
GLMC.glActiveTexture(GL32.GL_TEXTURE2);
@@ -43,8 +43,8 @@ public class GlDhVanillaFadeShader extends GlAbstractShaderRenderer
public int frameBuffer = -1;
private Mat4f inverseMcMvmProjMatrix;
private Mat4f inverseDhMvmProjMatrix;
private DhApiMat4f inverseMcMvmProjMatrix;
private DhApiMat4f inverseDhMvmProjMatrix;
private float levelMaxHeight;
@@ -136,21 +136,10 @@ public class GlDhVanillaFadeShader extends GlAbstractShaderRenderer
this.shader.setUniform(this.uOnlyRenderLods, Config.Client.Advanced.Debugging.lodOnlyMode.get());
}
public void setProjectionMatrix(DhApiMat4f mcModelViewMatrix, DhApiMat4f mcProjectionMatrix)
public void setProjectionMatrix(RenderParams renderParams)
{
Mat4f inverseMcModelViewProjectionMatrix = new Mat4f(mcProjectionMatrix);
inverseMcModelViewProjectionMatrix.multiply(mcModelViewMatrix);
inverseMcModelViewProjectionMatrix.invert();
this.inverseMcMvmProjMatrix = inverseMcModelViewProjectionMatrix;
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(mcProjectionMatrix);
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(mcModelViewMatrix);
Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(dhProjectionMatrix);
inverseDhModelViewProjectionMatrix.multiply(dhModelViewMatrix);
inverseDhModelViewProjectionMatrix.invert();
this.inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix;
this.inverseMcMvmProjMatrix = renderParams.mcInverseMvmProjectionMatrix;
this.inverseDhMvmProjMatrix = renderParams.dhInverseMvmProjectionMatrix;
}
public void setLevelMaxHeight(int levelMaxHeight) { this.levelMaxHeight = levelMaxHeight; }
@@ -185,7 +174,7 @@ public class GlDhVanillaFadeShader extends GlAbstractShaderRenderer
GLMC.disableBlend();
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(MC_RENDER.getDepthTextureId());
GLMC.glBindTexture(MC_RENDER.getGlDepthTextureId());
GL32.glUniform1i(this.uMcDepthTexture, 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
@@ -193,7 +182,7 @@ public class GlDhVanillaFadeShader extends GlAbstractShaderRenderer
GL32.glUniform1i(this.uDhDepthTexture, 1);
GLMC.glActiveTexture(GL32.GL_TEXTURE2);
GLMC.glBindTexture(MC_RENDER.getColorTextureId());
GLMC.glBindTexture(MC_RENDER.getGlColorTextureId());
GL32.glUniform1i(this.uCombinedMcDhColorTexture, 2);
GLMC.glActiveTexture(GL32.GL_TEXTURE3);
@@ -108,7 +108,7 @@ public class GlVanillaFadeRenderer implements IDhVanillaFadeRenderer
}
else
{
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, MC_RENDER.getColorTextureId(), 0);
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, MC_RENDER.getGlColorTextureId(), 0);
}
}
@@ -152,7 +152,7 @@ public class GlVanillaFadeRenderer implements IDhVanillaFadeRenderer
GlDhVanillaFadeShader.INSTANCE.frameBuffer = this.fadeFramebuffer;
GlDhVanillaFadeShader.INSTANCE.setProjectionMatrix(renderParams.mcModelViewMatrix, renderParams.mcProjectionMatrix);
GlDhVanillaFadeShader.INSTANCE.setProjectionMatrix(renderParams);
GlDhVanillaFadeShader.INSTANCE.setLevelMaxHeight(renderParams.clientLevelWrapper.getMaxHeight());
GlDhVanillaFadeShader.INSTANCE.render(renderParams);
@@ -19,6 +19,7 @@
package com.seibel.distanthorizons.common.render.openGl.postProcessing.fog;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiFogRenderParam;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLState;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
@@ -108,7 +109,7 @@ public class GlDhFogRenderer implements IDhFogRenderer
//region
@Override
public void render(RenderParams renderParams)
public void render(RenderParams renderParams, DhApiFogRenderParam fogRenderParams)
{
// GLState needed in MC 1.16.5 probably due to MC not manually setting each GL state they need before the next rendering step
try (GLState state = new GLState())
@@ -126,7 +127,7 @@ public class GlDhFogRenderer implements IDhFogRenderer
}
GlDhFogShader.INSTANCE.frameBuffer = this.fogFramebuffer;
GlDhFogShader.INSTANCE.setProjectionMatrix(renderParams.dhMvmProjMatrix);
GlDhFogShader.INSTANCE.prepUniformObjects(renderParams.dhMvmProjMatrix, fogRenderParams);
GlDhFogShader.INSTANCE.render(renderParams);
GlDhFogApplyShader.INSTANCE.fogTexture = this.fogTexture;
@@ -19,9 +19,9 @@
package com.seibel.distanthorizons.common.render.openGl.postProcessing.fog;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogColorMode;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiFogRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
@@ -37,8 +37,6 @@ import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import org.lwjgl.opengl.GL32;
import java.awt.*;
public class GlDhFogShader extends GlAbstractShaderRenderer
{
public static final GlDhFogShader INSTANCE = new GlDhFogShader();
@@ -51,6 +49,7 @@ public class GlDhFogShader extends GlAbstractShaderRenderer
public int frameBuffer;
private Mat4f inverseMvmProjMatrix;
private DhApiFogRenderParam fogRenderParams;
@@ -167,95 +166,58 @@ public class GlDhFogShader extends GlAbstractShaderRenderer
{
int lodDrawDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH;
if (this.inverseMvmProjMatrix != null)
{
this.shader.setUniform(this.uInvMvmProj, this.inverseMvmProjMatrix);
}
this.shader.setUniform(this.uInvMvmProj, this.inverseMvmProjMatrix);
// Fog uniforms
this.shader.setUniform(this.uFogColor, this.getFogColor(renderParams.partialTicks));
this.shader.setUniform(this.uFogColor, this.fogRenderParams.getFogColor());
this.shader.setUniform(this.uFogScale, 1.f / lodDrawDistance);
this.shader.setUniform(this.uFogVerticalScale, 1.f / MC.getWrappedClientLevel().getMaxHeight());
// only used for debugging
this.shader.setUniform(this.uFogDebugMode, 0); // 1 = render everything with fog color // 7 = use debug rendering
this.shader.setUniform(this.uFogFalloffType, Config.Client.Advanced.Graphics.Fog.farFogFalloff.get().value);
this.shader.setUniform(this.uFogDebugMode, 0); // 0 = normal // 1 = render everything with fog color // 7 = use debug rendering
this.shader.setUniform(this.uFogFalloffType, this.fogRenderParams.getFarFogFalloff().value);
// fog config
float farFogStart = Config.Client.Advanced.Graphics.Fog.farFogStart.get();
float farFogEnd = Config.Client.Advanced.Graphics.Fog.farFogEnd.get();
float farFogMin = Config.Client.Advanced.Graphics.Fog.farFogMin.get();
float farFogMax = Config.Client.Advanced.Graphics.Fog.farFogMax.get();
float farFogDensity = Config.Client.Advanced.Graphics.Fog.farFogDensity.get();
// override fog if underwater
if (MC_RENDER.isFogStateSpecial())
{
// hide everything behind fog
farFogStart = 0.0f;
farFogEnd = 0.0f;
}
this.shader.setUniform(this.uFarFogStart, farFogStart);
this.shader.setUniform(this.uFarFogLength, farFogEnd - farFogStart);
this.shader.setUniform(this.uFarFogMin, farFogMin);
this.shader.setUniform(this.uFarFogRange, farFogMax - farFogMin);
this.shader.setUniform(this.uFarFogDensity, farFogDensity);
this.shader.setUniform(this.uFarFogStart, this.fogRenderParams.getFarFogStartPercent());
this.shader.setUniform(this.uFarFogLength, this.fogRenderParams.getFarFogEndPercent() - this.fogRenderParams.getFarFogStartPercent());
this.shader.setUniform(this.uFarFogMin, this.fogRenderParams.getFarFogMinThickness());
this.shader.setUniform(this.uFarFogRange, this.fogRenderParams.getFarFogMaxThickness() - this.fogRenderParams.getFarFogMinThickness());
this.shader.setUniform(this.uFarFogDensity, this.fogRenderParams.getFarFogDensity());
// height config
EDhApiHeightFogMixMode heightFogMixingMode = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMixMode.get();
boolean heightFogEnabled = heightFogMixingMode != EDhApiHeightFogMixMode.SPHERICAL && heightFogMixingMode != EDhApiHeightFogMixMode.CYLINDRICAL;
EDhApiHeightFogMixMode heightFogMixingMode = this.fogRenderParams.getHeightFogMixingMode();
boolean heightFogEnabled =
heightFogMixingMode != EDhApiHeightFogMixMode.SPHERICAL
&& heightFogMixingMode != EDhApiHeightFogMixMode.CYLINDRICAL;
boolean useSphericalFog = heightFogMixingMode == EDhApiHeightFogMixMode.SPHERICAL;
EDhApiHeightFogDirection heightFogCameraDirection = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDirection.get();
EDhApiHeightFogDirection heightFogDirection = this.fogRenderParams.getHeightFogDirection();
float heightFogStart = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogStart.get();
float heightFogEnd = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogEnd.get();
float heightFogMin = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMin.get();
float heightFogMax = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMax.get();
float heightFogDensity = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDensity.get();
this.shader.setUniform(this.uHeightFogStart, heightFogStart);
this.shader.setUniform(this.uHeightFogLength, heightFogEnd - heightFogStart);
this.shader.setUniform(this.uHeightFogMin, heightFogMin);
this.shader.setUniform(this.uHeightFogRange, heightFogMax - heightFogMin);
this.shader.setUniform(this.uHeightFogDensity, heightFogDensity);
this.shader.setUniform(this.uHeightFogStart, this.fogRenderParams.getHeightFogStartPercent());
this.shader.setUniform(this.uHeightFogLength, this.fogRenderParams.getHeightFogEndPercent() - this.fogRenderParams.getHeightFogStartPercent());
this.shader.setUniform(this.uHeightFogMin, this.fogRenderParams.getFarFogMinThickness());
this.shader.setUniform(this.uHeightFogRange, this.fogRenderParams.getFarFogMaxThickness() - this.fogRenderParams.getFarFogMinThickness());
this.shader.setUniform(this.uHeightFogDensity, this.fogRenderParams.getFarFogDensity());
this.shader.setUniform(this.uHeightFogEnabled, heightFogEnabled);
this.shader.setUniform(this.uHeightFogFalloffType, Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogFalloff.get().value);
this.shader.setUniform(this.uHeightFogBaseHeight, Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogBaseHeight.get());
this.shader.setUniform(this.uHeightBasedOnCamera, heightFogCameraDirection.basedOnCamera);
this.shader.setUniform(this.uHeightFogAppliesUp, heightFogCameraDirection.fogAppliesUp);
this.shader.setUniform(this.uHeightFogAppliesDown, heightFogCameraDirection.fogAppliesDown);
this.shader.setUniform(this.uHeightFogFalloffType, this.fogRenderParams.getHeightFogFalloff().value);
this.shader.setUniform(this.uHeightFogBaseHeight, this.fogRenderParams.getHeightFogBaseHeight());
this.shader.setUniform(this.uHeightBasedOnCamera, heightFogDirection.basedOnCamera);
this.shader.setUniform(this.uHeightFogAppliesUp, heightFogDirection.fogAppliesUp);
this.shader.setUniform(this.uHeightFogAppliesDown, heightFogDirection.fogAppliesDown);
this.shader.setUniform(this.uUseSphericalFog, useSphericalFog);
this.shader.setUniform(this.uHeightFogMixingMode, heightFogMixingMode.value);
this.shader.setUniform(this.uCameraBlockYPos, (float)MC_RENDER.getCameraExactPosition().y);
}
private Color getFogColor(float partialTicks)
{
Color fogColor;
if (Config.Client.Advanced.Graphics.Fog.colorMode.get() == EDhApiFogColorMode.USE_SKY_COLOR)
{
fogColor = MC_RENDER.getSkyColor();
}
else
{
fogColor = MC_RENDER.getFogColor(partialTicks);
}
return fogColor;
}
public void setProjectionMatrix(DhApiMat4f modelViewProjectionMatrix)
public void prepUniformObjects(DhApiMat4f modelViewProjectionMatrix, DhApiFogRenderParam fogRenderParams)
{
this.inverseMvmProjMatrix = new Mat4f(modelViewProjectionMatrix);
this.inverseMvmProjMatrix.invert();
this.fogRenderParams = fogRenderParams;
}
//endregion
@@ -46,6 +46,11 @@ public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiS
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
private static final Vec3f MODEL_POS = new Vec3f();
/** single event object used to reduce GC pressure */
private static final DhApiBeforeBufferRenderEvent.EventParam BEFORE_BUFFER_RENDER_EVENT_PARAM = new DhApiBeforeBufferRenderEvent.EventParam();
private boolean init = false;
@@ -289,6 +294,9 @@ public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiS
GLMC.disableBlend();
}
// needs to be triggered after DH attempts to set the GL state so that Iris
// can override it as needed
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam.apiCopy);
@@ -311,19 +319,26 @@ public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiS
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
if (!bufferContainer.buffersUploaded)
{
// make sure we don't accidentally try
// rendering a buffer that is (or is going to be) freed
continue;
}
// set uniforms and fire events
{
Vec3d camPos = renderEventParam.exactCameraPosition;
Vec3f modelPos = new Vec3f(
MODEL_POS.set(
(float) (bufferContainer.minCornerBlockPos.getX() - camPos.x),
(float) (bufferContainer.minCornerBlockPos.getY() - camPos.y),
(float) (bufferContainer.minCornerBlockPos.getZ() - camPos.z));
BEFORE_BUFFER_RENDER_EVENT_PARAM.update(renderEventParam, MODEL_POS);
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bind();
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.setModelOffsetPos(modelPos);
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.setModelOffsetPos(MODEL_POS);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, new DhApiBeforeBufferRenderEvent.EventParam(renderEventParam, modelPos));
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, BEFORE_BUFFER_RENDER_EVENT_PARAM);
}
IVertexBufferWrapper[] vertexBuffers = (opaquePass ? bufferContainer.vboOpaqueWrappers : bufferContainer.vboTransparentWrappers);
@@ -335,25 +350,45 @@ public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiS
continue;
}
if (vbo.getVertexCount() == 0)
// for lock information please view the lock's javadocs
long vboReadStamp = vbo.renderStampLock.readLock();
long iboReadStamp = vbo.getQuadIBO().renderStampLock.readLock();
try
{
continue;
// don't render empty sections
if (vbo.getVertexCount() == 0)
{
continue;
}
// don't render deleted VBOs (this will crash the driver/game)
if (vbo.getId() == 0
|| vbo.getQuadIBO().getId() == 0)
{
continue;
}
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
int indexCount = (int) (vbo.getVertexCount() * 1.5);
vbo.bind();
vbo.getQuadIBO().bind();
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bindVertexBuffer(vbo.getId());
GL32.glDrawElements(
GL32.GL_TRIANGLES,
indexCount,
vbo.getQuadIBO().getGlType(), 0);
vbo.unbind();
vbo.getQuadIBO().unbind();
}
finally
{
vbo.renderStampLock.unlock(vboReadStamp);
vbo.getQuadIBO().renderStampLock.unlock(iboReadStamp);
}
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
int indexCount = (int)(vbo.getVertexCount() * 1.5);
vbo.bind();
vbo.getQuadIBO().bind();
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bindVertexBuffer(vbo.getId());
GL32.glDrawElements(
GL32.GL_TRIANGLES,
indexCount,
vbo.getQuadIBO().getGlType(), 0);
vbo.unbind();
vbo.getQuadIBO().unbind();
}
}
}
@@ -22,23 +22,34 @@ package com.seibel.distanthorizons.common.util;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
#if MC_VER <= MC_1_12_2
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
#else
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.LevelAccessor;
#endif
public class ProxyUtil
{
public static ILevelWrapper getLevelWrapper(LevelAccessor level)
public static ILevelWrapper getLevelWrapper(
#if MC_VER <= MC_1_12_2 World #else LevelAccessor #endif level
)
{
ILevelWrapper levelWrapper;
if (level instanceof ServerLevel)
if (level instanceof #if MC_VER <= MC_1_12_2 WorldServer #else ServerLevel #endif)
{
levelWrapper = ServerLevelWrapper.getWrapper((ServerLevel) level);
levelWrapper = ServerLevelWrapper.getWrapper(
#if MC_VER <= MC_1_12_2 (WorldServer) #else (ServerLevel) #endif level
);
}
else
{
levelWrapper = ClientLevelWrapper.getWrapper((ClientLevel) level);
levelWrapper = ClientLevelWrapper.getWrapper(
#if MC_VER <= MC_1_12_2 (WorldClient) #else (ClientLevel) #endif level
);
}
return levelWrapper;
@@ -19,11 +19,12 @@
package com.seibel.distanthorizons.common.wrappers;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderObjectFactory;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhRenderApiDefinition;
import com.seibel.distanthorizons.common.render.openGl.GlDhRenderApiDefinition;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
import com.seibel.distanthorizons.common.wrappers.gui.classicConfig.ClassicConfigGUI;
import com.seibel.distanthorizons.common.wrappers.gui.LangWrapper;
@@ -80,28 +81,39 @@ public class DependencySetup
SingletonInjector.INSTANCE.bind(IConfigGui.class, ClassicConfigGUI.CONFIG_CORE_INTERFACE);
}
private static boolean renderingApiBindingsSet = false;
/** will be called from a DH thread, not the render thread */
public static void setRenderingApiBindings()
public synchronized static void setRenderingApiBindings()
{
EDhApiRenderApi renderingApiEnum = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
if (renderingApiEnum == EDhApiRenderApi.AUTO)
// shouldn't happen, but there was a single report that this method was triggered twice
if (renderingApiBindingsSet)
{
LOGGER.warn("Rendering bindings already set, skipping. How did this happen?");
return;
}
renderingApiBindingsSet = true;
EDhApiRenderingEngine renderingApiEnum = Config.Client.Advanced.Graphics.Experimental.renderingEngine.get();
if (renderingApiEnum == EDhApiRenderingEngine.AUTO)
{
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
renderingApiEnum = versionConstants.getDefaultRenderingApi();
renderingApiEnum = versionConstants.getDefaultRenderingEngine();
}
LOGGER.info("Setting DH Rendering API to: ["+renderingApiEnum+"].");
LOGGER.info("Setting DH Rendering API to: ["+renderingApiEnum+"]...");
boolean validApi;
AbstractDhRenderApiDefinition renderDefinition;
if (renderingApiEnum == EDhApiRenderApi.OPEN_GL)
if (renderingApiEnum == EDhApiRenderingEngine.OPEN_GL)
{
validApi = true;
renderDefinition = new GlDhRenderApiDefinition();
}
else if (renderingApiEnum == EDhApiRenderApi.BLAZE_3D)
else if (renderingApiEnum == EDhApiRenderingEngine.BLAZE_3D)
{
#if MC_VER <= MC_1_21_10
validApi = false;
@@ -122,14 +134,24 @@ public class DependencySetup
// crash if an invalid API is set
if (!validApi)
{
String message = "["+renderingApiEnum+"] is not supported on this version of Minecraft, reverting to ["+EDhApiRenderApi.AUTO+"].";
String message = "["+renderingApiEnum+"] is not supported on this version of Minecraft, reverting to ["+ EDhApiRenderingEngine.AUTO+"].";
LOGGER.fatal(message);
Config.Client.Advanced.Graphics.Experimental.renderingEngine.set(EDhApiRenderingEngine.AUTO);
throw new IllegalStateException(message);
}
// crash if the rendering API set doesn't match Minecraft's
EDhApiRenderingApi mcRenderApi = MinecraftRenderWrapper.INSTANCE.getMcRenderingApi();
if (mcRenderApi != renderDefinition.getRenderApi())
{
String message = "["+renderDefinition.getApiName()+"] cannot be used due to it's API ["+renderDefinition.getRenderApi().name()+"] not matching what Minecraft is currently set to use. Please either change Minecraft's rendering API or Distant Horizons'.";
LOGGER.fatal(message);
Config.Client.Advanced.Graphics.Experimental.renderingApi.set(EDhApiRenderApi.AUTO);
throw new IllegalStateException(message);
}
renderDefinition.bindRenderers();
LOGGER.info("DH Rendering successfully bound to: ["+renderDefinition.getApiName()+"]...");
}
@@ -26,9 +26,15 @@ import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.util.math.Mat4f;
#if MC_VER <= MC_1_12_2
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
#else
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.ChunkPos;
#endif
/**
* This class converts to and from Minecraft objects (Ex: Matrix4f)
@@ -39,15 +45,17 @@ import net.minecraft.world.level.ChunkPos;
*/
public class McObjectConverter
{
private static int bufferIndex(int x, int y)
{
return y * 4 + x;
}
//========//
// matrix //
//========//
//region
/** 4x4 float matrix converter */
public static Mat4f Convert(
#if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
#if MC_VER <= MC_1_12_2 org.joml.Matrix4f
#elif MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
#elif MC_VER < MC_1_21_6 org.joml.Matrix4f
#else org.joml.Matrix4fc
#endif
@@ -56,21 +64,24 @@ public class McObjectConverter
FloatBuffer buffer = FloatBuffer.allocate(16);
storeMatrix(mcMatrix, buffer);
Mat4f matrix = new Mat4f(buffer);
#if MC_VER < MC_1_19_4
#if MC_VER > MC_1_12_2 && MC_VER < MC_1_19_4
matrix.transpose(); // In 1.19.3 and later, we no longer need to transpose it
#endif
return matrix;
}
/** Taken from Minecraft's com.mojang.math.Matrix4f class from 1.18.2 */
private static void storeMatrix(
#if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
#if MC_VER <= MC_1_12_2 org.joml.Matrix4f
#elif MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
#elif MC_VER < MC_1_21_6 org.joml.Matrix4f
#else org.joml.Matrix4fc
#endif
matrix,
FloatBuffer buffer)
{
#if MC_VER < MC_1_19_4
#if MC_VER <= MC_1_12_2
matrix.get(buffer);
#elif MC_VER < MC_1_19_4
matrix.store(buffer);
#else
// Mojang starts to use joml's Matrix4f libary in 1.19.3 so we copy their store method and use it here if its newer than 1.19.3
@@ -92,37 +103,85 @@ public class McObjectConverter
buffer.put(bufferIndex(3, 3), matrix.m33());
#endif
}
private static int bufferIndex(int x, int y) { return y * 4 + x; }
//endregion
static final Direction[] directions;
static final EDhDirection[] lodDirections;
//===========//
// direction //
//===========//
//region
#if MC_VER <= MC_1_12_2
private static final EnumFacing[] mcDirections;
#else
private static final Direction[] mcDirections;
#endif
private static final EDhDirection[] dhDirections;
static
{
EDhDirection[] lodDirs = EDhDirection.values();
directions = new Direction[lodDirs.length];
lodDirections = new EDhDirection[lodDirs.length];
#if MC_VER <= MC_1_12_2
mcDirections = new EnumFacing[lodDirs.length];
#else
mcDirections = new Direction[lodDirs.length];
#endif
dhDirections = new EDhDirection[lodDirs.length];
for (EDhDirection lodDir : lodDirs)
{
Direction dir;
#if MC_VER <= MC_1_12_2
EnumFacing dir;
#else
Direction dir;
#endif
switch (lodDir.name().toUpperCase())
{
case "DOWN":
#if MC_VER <= MC_1_12_2
dir = EnumFacing.DOWN;
#else
dir = Direction.DOWN;
#endif
break;
case "UP":
#if MC_VER <= MC_1_12_2
dir = EnumFacing.UP;
#else
dir = Direction.UP;
#endif
break;
case "NORTH":
#if MC_VER <= MC_1_12_2
dir = EnumFacing.NORTH;
#else
dir = Direction.NORTH;
#endif
break;
case "SOUTH":
#if MC_VER <= MC_1_12_2
dir = EnumFacing.SOUTH;
#else
dir = Direction.SOUTH;
#endif
break;
case "WEST":
#if MC_VER <= MC_1_12_2
dir = EnumFacing.WEST;
#else
dir = Direction.WEST;
#endif
break;
case "EAST":
#if MC_VER <= MC_1_12_2
dir = EnumFacing.EAST;
#else
dir = Direction.EAST;
#endif
break;
default:
dir = null;
@@ -131,13 +190,37 @@ public class McObjectConverter
if (dir == null)
{
throw new IllegalArgumentException("Invalid direction on init mapping: " + lodDir);
throw new IllegalArgumentException("Invalid direction on init mapping: [" + lodDir + "].");
}
directions[lodDir.ordinal()] = dir;
lodDirections[dir.ordinal()] = lodDir;
mcDirections[lodDir.ordinal()] = dir;
dhDirections[dir.ordinal()] = lodDir;
}
}
#if MC_VER <= MC_1_12_2
public static EnumFacing Convert(EDhDirection lodDirection)
#else
public static Direction Convert(EDhDirection lodDirection)
#endif
{ return mcDirections[lodDirection.ordinal()]; }
#if MC_VER <= MC_1_12_2
public static EDhDirection Convert(EnumFacing direction)
#else
public static EDhDirection Convert(Direction direction)
#endif
{ return dhDirections[direction.ordinal()]; }
//endregion
//==================//
// position objects //
//==================//
//region
public static BlockPos Convert(DhBlockPos wrappedPos) { return new BlockPos(wrappedPos.getX(), wrappedPos.getY(), wrappedPos.getZ()); }
public static ChunkPos Convert(DhChunkPos wrappedPos) { return new ChunkPos(wrappedPos.getX(), wrappedPos.getZ()); }
@@ -150,7 +233,8 @@ public class McObjectConverter
#endif
}
public static Direction Convert(EDhDirection lodDirection) { return directions[lodDirection.ordinal()]; }
public static EDhDirection Convert(Direction direction) { return lodDirections[direction.ordinal()]; }
//endregion
}
@@ -19,7 +19,7 @@
package com.seibel.distanthorizons.common.wrappers;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
public class VersionConstants implements IVersionConstants
@@ -51,7 +51,10 @@ public class VersionConstants implements IVersionConstants
// it can't load client classes when running as a dedicated server,
// which was how we were dynamically accessing the MC version string
#if MC_VER == MC_1_16_5
#if MC_VER == MC_1_12_2
return "1.12.2";
#elif MC_VER == MC_1_16_5
return "1.16.5";
#elif MC_VER == MC_1_17_1
@@ -95,6 +98,8 @@ public class VersionConstants implements IVersionConstants
return "1.21.11";
#elif MC_VER == MC_26_1_2
return "26.1.2";
#elif MC_VER == MC_26_2_0
return "26.2.0";
#else
ERROR MC version constant missing
#endif
@@ -102,12 +107,12 @@ public class VersionConstants implements IVersionConstants
}
@Override
public EDhApiRenderApi getDefaultRenderingApi()
public EDhApiRenderingEngine getDefaultRenderingEngine()
{
#if MC_VER <= MC_1_21_11
return EDhApiRenderApi.OPEN_GL;
return EDhApiRenderingEngine.OPEN_GL;
#else
return EDhApiRenderApi.BLAZE_3D;
return EDhApiRenderingEngine.BLAZE_3D;
#endif
}
@@ -46,17 +46,30 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import net.minecraft.client.multiplayer.ClientLevel;
#if MC_VER > MC_1_17_1
import net.minecraft.core.Holder;
#endif
#if MC_VER <= MC_1_12_2
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.chunk.Chunk;
#else
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
#endif
import java.io.IOException;
import java.util.HashSet;
/**
* This handles creating abstract wrapper objects.
@@ -115,7 +128,7 @@ public class WrapperFactory implements IWrapperFactory
throw new ClassCastException("levelWrapper must be returned by DH and of type ["+ILevelWrapper.class.getName()+"].");
}
return BiomeWrapper.deserialize(resourceLocationString, (ILevelWrapper)levelWrapper);
return BiomeWrapper.deserialize(resourceLocationString, (ILevelWrapper)levelWrapper);
}
@Override
public IDhApiBlockStateWrapper getDefaultBlockStateWrapper(String resourceLocationString, IDhApiLevelWrapper levelWrapper) throws IOException, ClassCastException
@@ -125,19 +138,19 @@ public class WrapperFactory implements IWrapperFactory
throw new ClassCastException("Invalid ["+IDhApiLevelWrapper.class.getSimpleName()+"] value given. Level wrapper object must be one given by the DH API (it can't be a custom implementation), specifically of type ["+ILevelWrapper.class.getName()+"].");
}
return BlockStateWrapper.deserialize(resourceLocationString, (ILevelWrapper)levelWrapper);
return BlockStateWrapper.deserialize(resourceLocationString, (ILevelWrapper)levelWrapper);
}
@Override
public IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BiomeWrapper.deserialize(str, levelWrapper); }
@Override
@Override
public IBiomeWrapper getPlainsBiomeWrapper(ILevelWrapper levelWrapper)
{
try
{
return BiomeWrapper.deserialize(BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING, levelWrapper);
}
catch (IOException e)
catch (IOException e)
{
throw new LodUtil.AssertFailureException("Unable to parse plains resource string ["+BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING+"], error:\n " + e.getMessage());
}
@@ -172,7 +185,8 @@ public class WrapperFactory implements IWrapperFactory
*/
public IChunkWrapper createChunkWrapper(Object[] objectArray) throws ClassCastException
{
if (objectArray.length == 1 && objectArray[0] instanceof IChunkWrapper)
if (objectArray.length == 1
&& objectArray[0] instanceof IChunkWrapper)
{
try
{
@@ -186,41 +200,102 @@ public class WrapperFactory implements IWrapperFactory
}
}
//#if MC_VER <= MC_1_XX_X
else if (objectArray.length == 2)
{
// correct number of parameters from the API
// chunk
if (!(objectArray[0] instanceof ChunkAccess))
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
ChunkAccess chunk = (ChunkAccess) objectArray[0];
// level / light source
if (!(objectArray[1] instanceof Level))
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
// the level is needed for the DH level wrapper...
Level level = (Level) objectArray[1];
// level wrapper
ILevelWrapper levelWrapper = level.isClientSide()
? ClientLevelWrapper.getWrapper((ClientLevel)level)
: ServerLevelWrapper.getWrapper((ServerLevel)level);
return new ChunkWrapper(chunk, levelWrapper);
}
// incorrect number of parameters from the API
else
else if (objectArray.length != 2)
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
//#endif
// correct number of parameters from the API
//=======//
// chunk //
//=======//
//region
boolean chunkClassCorrect;
#if MC_VER <= MC_1_12_2
chunkClassCorrect = (objectArray[0] instanceof Chunk);
#else
chunkClassCorrect = (objectArray[0] instanceof ChunkAccess);
#endif
if (!chunkClassCorrect)
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
#if MC_VER <= MC_1_12_2
Chunk chunk = (Chunk) objectArray[0];
#else
ChunkAccess chunk = (ChunkAccess) objectArray[0];
#endif
//endregion
//=======//
// level //
//=======//
//region
boolean levelClassCorrect;
#if MC_VER <= MC_1_12_2
levelClassCorrect = (objectArray[1] instanceof World);
#else
levelClassCorrect = (objectArray[1] instanceof Level);
#endif
if (!levelClassCorrect)
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
#if MC_VER <= MC_1_12_2
World level = (World) objectArray[1];
#else
Level level = (Level) objectArray[1];
#endif
//endregion
//===============//
// level wrapper //
//===============//
//region
boolean isClientSide;
#if MC_VER <= MC_1_12_2
isClientSide = !level.isRemote;
#else
isClientSide = level.isClientSide();
#endif
ILevelWrapper levelWrapper;
if (isClientSide)
{
#if MC_VER <= MC_1_12_2
levelWrapper = ClientLevelWrapper.getWrapper((WorldClient)level);
#else
levelWrapper = ClientLevelWrapper.getWrapper((ClientLevel)level);
#endif
}
else
{
#if MC_VER <= MC_1_12_2
levelWrapper = ServerLevelWrapper.getWrapper((WorldServer)level);
#else
levelWrapper = ServerLevelWrapper.getWrapper((ServerLevel)level);
#endif
}
//endregion
return new ChunkWrapper(chunk, levelWrapper);
}
/**
* Note: when this is updated for different MC versions,
@@ -230,13 +305,19 @@ public class WrapperFactory implements IWrapperFactory
{
String[] expectedClassNames;
//#if MC_VER <= MC_1_XX_X
expectedClassNames = new String[]
{
ChunkAccess.class.getName(),
"[ServerLevel] or [ClientLevel]" // Classes are not referenced by names to avoid exception when one of them is missing
};
//#endif
#if MC_VER <= MC_1_12_2
expectedClassNames = new String[]
{
Chunk.class.getName(),
"[WorldClient] or [WorldServer]" // Classes are not referenced by names to avoid exception when one of them is missing
};
#else
expectedClassNames = new String[]
{
ChunkAccess.class.getName(),
"[ServerLevel] or [ClientLevel]" // Classes are not referenced by names to avoid exception when one of them is missing
};
#endif
return createWrapperErrorMessage("Chunk wrapper", expectedClassNames, objectArray);
}
@@ -258,7 +339,7 @@ public class WrapperFactory implements IWrapperFactory
// documentation should be in the API interface
public IDhApiBiomeWrapper getBiomeWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper)
public IDhApiBiomeWrapper getBiomeWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper)
{
// confirm the API level wrapper is also a Core wrapper
if (!(levelWrapper instanceof ILevelWrapper))
@@ -322,19 +403,29 @@ public class WrapperFactory implements IWrapperFactory
//#if MC_VER <= MC_1_XX_X
if (objectArray.length != 1)
{
throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray));
}
if (!(objectArray[0] instanceof BlockState))
boolean blockClassCorrect;
#if MC_VER <= MC_1_12_2
blockClassCorrect = (objectArray[0] instanceof IBlockState);
#else
blockClassCorrect = (objectArray[0] instanceof BlockState);
#endif
if (!blockClassCorrect)
{
throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray));
}
#if MC_VER <= MC_1_12_2
IBlockState blockState = (IBlockState) objectArray[0];
return BlockStateWrapper.fromBlockState(blockState, coreLevelWrapper);
#else
BlockState blockState = (BlockState) objectArray[0];
return BlockStateWrapper.fromBlockState(blockState, coreLevelWrapper);
//#endif
#endif
}
/**
* Note: when this is updated for different MC versions,
@@ -344,7 +435,9 @@ public class WrapperFactory implements IWrapperFactory
{
String[] expectedClassNames;
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
#if MC_VER <= MC_1_12_2
expectedClassNames = new String[] { IBlockState.class.getName() };
#elif MC_VER <= MC_1_17_1
expectedClassNames = new String[] { Biome.class.getName() };
#else
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
@@ -357,7 +450,6 @@ public class WrapperFactory implements IWrapperFactory
//================//
// helper methods //
//================//
@@ -367,8 +459,8 @@ public class WrapperFactory implements IWrapperFactory
{
// error header
StringBuilder message = new StringBuilder(
wrapperName + " creation failed. \n" +
"Expected object array parameters: \n");
wrapperName + " creation failed. \n" +
"Expected object array parameters: \n");
// expected parameters
@@ -1,5 +1,5 @@
package com.seibel.distanthorizons.common.wrappers.block;
#if MC_VER > MC_1_12_2
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.BlockBiomeWrapperPair;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
@@ -11,10 +11,14 @@ import com.seibel.distanthorizons.core.util.FullDataPointUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.Minecraft;
#if MC_VER <= MC_1_12_2
import net.minecraft.world.biome.Biome;
#else
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.biome.Biome;
#endif
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
@@ -45,8 +49,6 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
#endif
private static final ConcurrentHashMap<BlockBiomeWrapperPair, Integer> COLOR_BY_BLOCK_BIOME_PAIR = new ConcurrentHashMap<>();
/** returned if the color cache is incomplete */
public static final int INVALID_COLOR = -1;
protected BiomeWrapper biomeWrapper;
@@ -98,7 +100,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
* Can be called by DH directly, skipping some of MC's logic
* to speed up tint getting slightly.
*
* @return {@link AbstractDhTintGetter#INVALID_COLOR} if any of the biomes needed for this position
* @return {@link ClientBlockStateColorCache#INVALID_COLOR} if any of the biomes needed for this position
* were not cached. In that case calling {@link AbstractDhTintGetter#getBlockTint(BlockPos, ColorResolver)}
* will need to be called by MC's ColorResolver so we can
* populate the color cache.
@@ -159,9 +161,9 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
int id = FullDataPointUtil.getId(dataPoint);
BiomeWrapper biomeWrapper = (BiomeWrapper) this.fullDataSource.mapping.getBiomeWrapper(id);
int color = this.tryGetClientBiomeColor(colorResolver, biomeWrapper);
if (color == INVALID_COLOR)
if (color == ClientBlockStateColorCache.INVALID_COLOR)
{
return INVALID_COLOR;
return ClientBlockStateColorCache.INVALID_COLOR;
}
@@ -210,7 +212,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
// no color resolver is present,
// the cache needs to be populated before
// we can use the fast path
return INVALID_COLOR;
return ClientBlockStateColorCache.INVALID_COLOR;
}
@@ -343,9 +345,9 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
//===========//
// set color //
//===========//
//=================//
// static handlers //
//=================//
//region
/**
@@ -358,8 +360,11 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
COLOR_BY_BLOCK_BIOME_PAIR.put(pair, colorInt);
}
public static void clear() { COLOR_BY_BLOCK_BIOME_PAIR.clear(); }
//endregion
}
#endif
@@ -28,12 +28,15 @@ import java.util.concurrent.ConcurrentMap;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import net.minecraft.world.level.Level;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
#if MC_VER > MC_1_12_2
import net.minecraft.world.level.Level;
#endif
#if MC_VER <= MC_1_12_2
#elif MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
import net.minecraft.core.Registry;
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
import net.minecraft.core.Holder;
@@ -45,14 +48,21 @@ import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
#endif
#if MC_VER <= MC_1_21_10
#if MC_VER <= MC_1_12_2
import net.minecraft.util.ResourceLocation;
#elif MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
import net.minecraft.core.component.DataComponentMap;
#endif
#if MC_VER <= MC_1_12_2
import net.minecraft.world.biome.Biome;
#else
import net.minecraft.world.level.biome.Biome;
#endif
#if MC_VER >= MC_1_18_2
import net.minecraft.world.level.biome.Biomes;
@@ -108,8 +118,13 @@ public class BiomeWrapper implements IBiomeWrapper
//==============//
// constructors //
//==============//
//region
public static BiomeWrapper getBiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome, ILevelWrapper levelWrapper)
#if MC_VER < MC_1_18_2
public static BiomeWrapper getBiomeWrapper(Biome biome, ILevelWrapper levelWrapper)
#else
public static BiomeWrapper getBiomeWrapper(Holder<Biome> biome, ILevelWrapper levelWrapper)
#endif
{
if (biome == null)
{
@@ -129,7 +144,12 @@ public class BiomeWrapper implements IBiomeWrapper
return newWrapper;
}
}
private BiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome, ILevelWrapper levelWrapper)
#if MC_VER < MC_1_18_2
private BiomeWrapper(Biome biome, ILevelWrapper levelWrapper)
#else
private BiomeWrapper(Holder<Biome> biome, ILevelWrapper levelWrapper)
#endif
{
this.biome = biome;
this.serialString = this.serialize(levelWrapper);
@@ -138,11 +158,14 @@ public class BiomeWrapper implements IBiomeWrapper
//LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]");
}
//endregion
//=========//
// methods //
//=========//
//region
@Override
public String getName()
@@ -188,11 +211,14 @@ public class BiomeWrapper implements IBiomeWrapper
@Override
public String toString() { return this.getSerialString(); }
//endregion
//=======================//
// serialization methods //
//=======================//
//region
public String serialize(ILevelWrapper levelWrapper)
{
@@ -219,8 +245,10 @@ public class BiomeWrapper implements IBiomeWrapper
// generate the serial string //
#if MC_VER > MC_1_12_2
Level level = (Level)levelWrapper.getWrappedMcObject();
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
#endif
#if MC_VER <= MC_1_21_10
ResourceLocation resourceLocation;
@@ -228,7 +256,9 @@ public class BiomeWrapper implements IBiomeWrapper
Identifier resourceLocation;
#endif
#if MC_VER <= MC_1_17_1
#if MC_VER <= MC_1_12_2
resourceLocation = biome.getRegistryName();
#elif MC_VER <= MC_1_17_1
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome);
#elif MC_VER <= MC_1_19_2
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value());
@@ -293,11 +323,16 @@ public class BiomeWrapper implements IBiomeWrapper
{
try
{
#if MC_VER > MC_1_12_2
Level level = (Level) levelWrapper.getWrappedMcObject();
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
#endif
#if MC_VER <= MC_1_12_2
BiomeDeserializeResult deserializeResult = deserializeBiome(resourceLocationString);
#else
BiomeDeserializeResult deserializeResult = deserializeBiome(resourceLocationString, registryAccess);
#endif
if (!deserializeResult.success)
@@ -325,7 +360,11 @@ public class BiomeWrapper implements IBiomeWrapper
}
}
#if MC_VER <= MC_1_12_2
public static BiomeDeserializeResult deserializeBiome(String resourceLocationString) throws IOException
#else
public static BiomeDeserializeResult deserializeBiome(String resourceLocationString, net.minecraft.core.RegistryAccess registryAccess) throws IOException
#endif
{
// parse the resource location
int separatorIndex = resourceLocationString.indexOf(":");
@@ -356,7 +395,10 @@ public class BiomeWrapper implements IBiomeWrapper
boolean success;
#if MC_VER <= MC_1_17_1
#if MC_VER <= MC_1_12_2
Biome biome = Biome.REGISTRY.getObject(resourceLocation);
success = (biome != null);
#elif MC_VER <= MC_1_17_1
Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
success = (biome != null);
#elif MC_VER <= MC_1_19_2
@@ -400,10 +442,14 @@ public class BiomeWrapper implements IBiomeWrapper
return new BiomeDeserializeResult(success, biome);
}
//endregion
//================//
// helper classes //
//================//
//region
public static class BiomeDeserializeResult
{
@@ -413,14 +459,21 @@ public class BiomeWrapper implements IBiomeWrapper
public final Biome biome;
#else
public final Holder<Biome> biome;
#endif
#endif
public BiomeDeserializeResult(boolean success, #if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome)
#if MC_VER < MC_1_18_2
public BiomeDeserializeResult(boolean success, Biome biome)
#else
public BiomeDeserializeResult(boolean success, Holder<Biome> biome)
#endif
{
this.success = success;
this.biome = biome;
}
}
//endregion
}
@@ -32,12 +32,20 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrappe
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
#if MC_VER <= MC_1_12_2
import net.minecraft.block.*;
import net.minecraft.init.Blocks;
import net.minecraft.block.state.IBlockState;
import net.minecraft.block.properties.IProperty;
import net.minecraftforge.fluids.IFluidBlock;
#else
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.BeaconBeamBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.state.BlockState;
#endif
import com.seibel.distanthorizons.core.logging.DhLogger;
import java.awt.*;
@@ -61,7 +69,7 @@ import net.minecraft.world.level.Level;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.world.level.EmptyBlockGetter;
#else
#elif MC_VER > MC_1_12_2
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.Level;
import net.minecraft.core.BlockPos;
@@ -70,12 +78,15 @@ import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.core.Holder;
#endif
#if MC_VER <= MC_1_21_10
#if MC_VER <= MC_1_12_2
import net.minecraft.util.ResourceLocation;
#elif MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
#endif
public class BlockStateWrapper implements IBlockStateWrapper
{
/** example "minecraft:water" */
@@ -87,7 +98,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
// must be defined before AIR, otherwise a null pointer will be thrown
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
#if MC_VER <= MC_1_12_2
public static final ConcurrentHashMap<IBlockState, BlockStateWrapper> WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>();
#else
public static final ConcurrentHashMap<BlockState, BlockStateWrapper> WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>();
#endif
public static final ConcurrentHashMap<String, BlockStateWrapper> WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>();
public static final String AIR_STRING = "AIR";
@@ -114,7 +129,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
// properties //
@Nullable
#if MC_VER <= MC_1_12_2
public final IBlockState blockState;
#else
public final BlockState blockState;
#endif
/** technically final, but since it requires a method call to generate it can't be marked as such */
private String serialString;
private final int hashCode;
@@ -139,27 +158,71 @@ public class BlockStateWrapper implements IBlockStateWrapper
// constructors //
//==============//
//region
/**
* Can be faster than {@link BlockStateWrapper#fromBlockState(BlockState, ILevelWrapper)}
* Can be faster than BlockStateWrapper#fromBlockState(BlockState, ILevelWrapper)
* in cases where the same block state is expected to be referenced multiple times.
*/
#if MC_VER <= MC_1_12_2
public static BlockStateWrapper fromBlockState(IBlockState blockState, ILevelWrapper levelWrapper, IBlockStateWrapper guess)
#else
public static BlockStateWrapper fromBlockState(BlockState blockState, ILevelWrapper levelWrapper, IBlockStateWrapper guess)
#endif
{
BlockState guessBlockState = (guess == null || guess.isAir()) ? null : (BlockState) guess.getWrappedMcObject();
BlockState inputBlockState = (blockState == null || blockState.isAir()) ? null : blockState;
if (guess instanceof BlockStateWrapper
&& guessBlockState == inputBlockState)
{
return (BlockStateWrapper) guess;
}
else
if (guess == null)
{
return fromBlockState(blockState, levelWrapper);
}
// guess block state
BlockStateWrapper wrapperGuess = (BlockStateWrapper) guess;
#if MC_VER <= MC_1_12_2
IBlockState guessBlockState;
#else
BlockState guessBlockState;
#endif
if(isAir(wrapperGuess.blockState))
{
guessBlockState = null;
}
else
{
#if MC_VER <= MC_1_12_2
guessBlockState = (IBlockState) guess.getWrappedMcObject();
#else
guessBlockState = (BlockState) guess.getWrappedMcObject();
#endif
}
// input block state
#if MC_VER <= MC_1_12_2
IBlockState inputBlockState;
#else
BlockState inputBlockState;
#endif
if (isAir(blockState))
{
inputBlockState = null;
}
else
{
inputBlockState = blockState;
}
if (guessBlockState == inputBlockState)
{
return (BlockStateWrapper) guess;
}
return fromBlockState(blockState, levelWrapper);
}
#if MC_VER <= MC_1_12_2
public static BlockStateWrapper fromBlockState(@Nullable IBlockState blockState, ILevelWrapper levelWrapper)
#else
public static BlockStateWrapper fromBlockState(@Nullable BlockState blockState, ILevelWrapper levelWrapper)
#endif
{
// air is a special case
if (isAir(blockState))
@@ -167,24 +230,53 @@ public class BlockStateWrapper implements IBlockStateWrapper
return AIR;
}
// create a wrapper specifically for the API event to use
BlockStateWrapper apiWrapper = new BlockStateWrapper(blockState, levelWrapper, null);
DhApiBlockStateWrapperCreatedEvent.EventParam eventParam = new DhApiBlockStateWrapperCreatedEvent.EventParam(apiWrapper);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBlockStateWrapperCreatedEvent.class, eventParam);
if (!eventParam.getOverridesSet())
// pooling wrappers significantly improves chunk->LOD processing speed
// and also reduces GC pressure
BlockStateWrapper existingWrapper = WRAPPER_BY_BLOCK_STATE.get(blockState);
if (existingWrapper != null)
{
// no changes needed, use the existing object
return apiWrapper;
return existingWrapper;
}
// create a new wrapper using whatever overrides the API user set
BlockStateWrapper returnWrapper = new BlockStateWrapper(blockState, levelWrapper, eventParam);
return returnWrapper;
// synchronized so the API event only fires once per block
synchronized (WRAPPER_BY_BLOCK_STATE)
{
// if another thread already finished this block, use that wrapper
existingWrapper = WRAPPER_BY_BLOCK_STATE.get(blockState);
if (existingWrapper != null)
{
return existingWrapper;
}
// create a wrapper specifically for the API event to use
BlockStateWrapper apiWrapper = new BlockStateWrapper(blockState, levelWrapper, null);
DhApiBlockStateWrapperCreatedEvent.EventParam eventParam = new DhApiBlockStateWrapperCreatedEvent.EventParam(apiWrapper);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBlockStateWrapperCreatedEvent.class, eventParam);
if (!eventParam.getOverridesSet())
{
// no API changes needed, use the existing object
WRAPPER_BY_BLOCK_STATE.putIfAbsent(blockState, apiWrapper);
return apiWrapper;
}
else
{
// create a new wrapper using whatever overrides the API user set
BlockStateWrapper returnWrapper = new BlockStateWrapper(blockState, levelWrapper, eventParam);
WRAPPER_BY_BLOCK_STATE.putIfAbsent(blockState, returnWrapper);
return returnWrapper;
}
}
}
private BlockStateWrapper(
@Nullable BlockState blockState, ILevelWrapper levelWrapper,
@Nullable DhApiBlockStateWrapperCreatedEvent.EventParam overrideEventParam)
#if MC_VER <= MC_1_12_2
private BlockStateWrapper(@Nullable IBlockState blockState, ILevelWrapper levelWrapper, @Nullable DhApiBlockStateWrapperCreatedEvent.EventParam overrideEventParam)
#else
private BlockStateWrapper(@Nullable BlockState blockState, ILevelWrapper levelWrapper, @Nullable DhApiBlockStateWrapperCreatedEvent.EventParam overrideEventParam)
#endif
{
this.blockState = blockState;
this.serialString = serialize(blockState, levelWrapper);
@@ -202,11 +294,13 @@ public class BlockStateWrapper implements IBlockStateWrapper
}
else
{
#if MC_VER < MC_1_20_1
this.isLiquid = this.blockState.getMaterial().isLiquid() || !this.blockState.getFluidState().isEmpty();
#else
#if MC_VER <= MC_1_12_2
this.isLiquid = this.blockState.getMaterial().isLiquid() || this.blockState.getBlock() instanceof IFluidBlock;
#elif MC_VER < MC_1_20_1
this.isLiquid = this.blockState.getMaterial().isLiquid() || !this.blockState.getFluidState().isEmpty();
#else
this.isLiquid = !this.blockState.getFluidState().isEmpty();
#endif
#endif
}
}
@@ -306,9 +400,21 @@ public class BlockStateWrapper implements IBlockStateWrapper
&& !this.isBeaconBlock)
{
Block block = this.blockState.getBlock();
int colorInt;
#if MC_VER <= MC_1_12_2
if (block instanceof BlockStainedGlass)
{
colorInt = blockState.getValue(BlockStainedGlass.COLOR).getColorValue();
beaconTintColor = ColorUtil.toColorObjRGB(colorInt);
}
else if (block instanceof BlockStainedGlassPane)
{
colorInt = blockState.getValue(BlockStainedGlassPane.COLOR).getColorValue();
beaconTintColor = ColorUtil.toColorObjRGB(colorInt);
}
#else
if (block instanceof BeaconBeamBlock)
{
int colorInt;
#if MC_VER <= MC_1_19_4
colorInt = ((BeaconBeamBlock) block).getColor().getMaterialColor().col;
#else
@@ -317,6 +423,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
beaconTintColor = ColorUtil.toColorObjRGB(colorInt);
}
#endif
}
this.beaconTintColor = beaconTintColor;
@@ -366,8 +473,10 @@ public class BlockStateWrapper implements IBlockStateWrapper
if (this.blockState != null)
{
int mcColor = 0;
#if MC_VER < MC_1_20_1
#if MC_VER <= MC_1_12_2
mcColor = this.blockState.getMaterial().getMaterialMapColor().colorValue;
#elif MC_VER < MC_1_20_1
mcColor = this.blockState.getMaterial().getColor().col;
#else
mcColor = this.blockState.getMapColor(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).col;
@@ -394,7 +503,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
#if MC_VER < MC_1_20_1
this.isSolid = this.blockState.getMaterial().isSolid();
#else
this.isSolid = !this.blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty();
this.isSolid = !this.blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty();
#endif
}
}
@@ -405,76 +514,193 @@ public class BlockStateWrapper implements IBlockStateWrapper
// static constructor helpers //
//region
private static EDhApiBlockMaterial calculateEDhApiBlockMaterialId(
@Nullable BlockState blockState,
String lowercaseSerialString,
boolean isLiquid
)
#if MC_VER <= MC_1_12_2
private static EDhApiBlockMaterial calculateEDhApiBlockMaterialId(@Nullable IBlockState blockState, String lowercaseSerialString, boolean isLiquid)
#else
private static EDhApiBlockMaterial calculateEDhApiBlockMaterialId(@Nullable BlockState blockState, String lowercaseSerialString, boolean isLiquid)
#endif
{
if (blockState == null)
if (isAir(blockState))
{
return EDhApiBlockMaterial.AIR;
}
if (blockState.is(BlockTags.LEAVES)
//========//
// leaves //
//========//
//region
boolean isLeafBlock;
#if MC_VER <= MC_1_12_2
isLeafBlock = blockState.getBlock() instanceof BlockLeaves;
#else
isLeafBlock = blockState.is(BlockTags.LEAVES);
#endif
if (isLeafBlock
|| lowercaseSerialString.contains("bamboo")
|| lowercaseSerialString.contains("cactus")
|| lowercaseSerialString.contains("chorus_flower")
|| lowercaseSerialString.contains("mushroom")
)
)
{
return EDhApiBlockMaterial.LEAVES;
}
else if (blockState.is(Blocks.LAVA))
//endregion
//======//
// lava //
//======//
//region
boolean isLavaBlock;
#if MC_VER <= MC_1_12_2
isLavaBlock = blockState.getBlock() == Blocks.LAVA || blockState.getBlock() == Blocks.FLOWING_LAVA;
#else
isLavaBlock = blockState.is(Blocks.LAVA);
#endif
if (isLavaBlock)
{
return EDhApiBlockMaterial.LAVA;
}
else if (isLiquid
|| blockState.is(Blocks.WATER))
//endregion
//=======//
// water //
//=======//
//region
boolean isWaterBlock;
#if MC_VER <= MC_1_12_2
isWaterBlock = blockState.getBlock() == Blocks.WATER || blockState.getBlock() == Blocks.FLOWING_WATER;
#else
isWaterBlock = blockState.is(Blocks.WATER);
#endif
if (isLiquid
|| isWaterBlock)
{
return EDhApiBlockMaterial.WATER;
}
else if (blockState.getSoundType() == SoundType.WOOD
//endregion
//======//
// wood //
//======//
//region
boolean isWoodSoundingBlock;
#if MC_VER <= MC_1_12_2
isWoodSoundingBlock = blockState.getBlock().getSoundType() == SoundType.WOOD;
#else
isWoodSoundingBlock = blockState.getSoundType() == SoundType.WOOD;
#endif
boolean isCherryWood;
#if MC_VER <= MC_1_19_2
isCherryWood = false;
#else
isCherryWood = blockState.getSoundType() == SoundType.CHERRY_WOOD;
#endif
if (isWoodSoundingBlock
|| lowercaseSerialString.contains("root")
#if MC_VER >= MC_1_19_4
|| blockState.getSoundType() == SoundType.CHERRY_WOOD
#endif
)
|| isCherryWood
)
{
return EDhApiBlockMaterial.WOOD;
}
else if (blockState.getSoundType() == SoundType.METAL
#if MC_VER >= MC_1_19_2
|| blockState.getSoundType() == SoundType.COPPER
#endif
#if MC_VER >= MC_1_20_4
|| blockState.getSoundType() == SoundType.COPPER_BULB
|| blockState.getSoundType() == SoundType.COPPER_GRATE
#endif
)
//endregion
//=======//
// metal //
//=======//
//region
boolean isMetalSoundingBlock;
#if MC_VER <= MC_1_12_2
isMetalSoundingBlock = blockState.getBlock().getSoundType() == SoundType.METAL;
#else
isMetalSoundingBlock = blockState.getSoundType() == SoundType.METAL;
#endif
boolean isCopperSounding;
#if MC_VER <= MC_1_18_2
isCopperSounding = false;
#elif MC_VER <= MC_1_20_2
isCopperSounding = blockState.getSoundType() == SoundType.COPPER;
#else
isCopperSounding
= blockState.getSoundType() == SoundType.COPPER
|| blockState.getSoundType() == SoundType.COPPER_BULB
|| blockState.getSoundType() == SoundType.COPPER_GRATE;
#endif
if (isMetalSoundingBlock
|| isCopperSounding)
{
return EDhApiBlockMaterial.METAL;
}
else if (
lowercaseSerialString.contains("grass_block")
|| lowercaseSerialString.contains("grass_slab")
)
//endregion
//=======//
// grass //
//=======//
//region
if (lowercaseSerialString.contains("grass_block")
|| lowercaseSerialString.contains("grass_slab")
)
{
return EDhApiBlockMaterial.GRASS;
}
else if (
//endregion
//======//
// dirt //
//======//
//region
if (
lowercaseSerialString.contains("dirt")
|| lowercaseSerialString.contains("gravel")
|| lowercaseSerialString.contains("mud")
|| lowercaseSerialString.contains("podzol")
|| lowercaseSerialString.contains("mycelium")
)
|| lowercaseSerialString.contains("gravel")
|| lowercaseSerialString.contains("mud")
|| lowercaseSerialString.contains("podzol")
|| lowercaseSerialString.contains("mycelium")
)
{
return EDhApiBlockMaterial.DIRT;
}
//endregion
//===========//
// deepslate //
//===========//
//region
#if MC_VER >= MC_1_17_1
else if (blockState.getSoundType() == SoundType.DEEPSLATE
if (blockState.getSoundType() == SoundType.DEEPSLATE
|| blockState.getSoundType() == SoundType.DEEPSLATE_BRICKS
|| blockState.getSoundType() == SoundType.DEEPSLATE_TILES
|| blockState.getSoundType() == SoundType.POLISHED_DEEPSLATE
@@ -483,41 +709,75 @@ public class BlockStateWrapper implements IBlockStateWrapper
return EDhApiBlockMaterial.DEEPSLATE;
}
#endif
else if (lowercaseSerialString.contains("snow"))
{
return EDhApiBlockMaterial.SNOW;
}
else if (lowercaseSerialString.contains("sand"))
{
return EDhApiBlockMaterial.SAND;
}
else if (lowercaseSerialString.contains("terracotta"))
{
return EDhApiBlockMaterial.TERRACOTTA;
}
else if (blockState.is(BlockTags.BASE_STONE_NETHER))
//endregion
//============//
// netherrack //
//============//
//region
boolean isNetherRack;
#if MC_VER <= MC_1_12_2
isNetherRack = blockState.getBlock() == Blocks.NETHERRACK;
#else
isNetherRack = blockState.is(BlockTags.BASE_STONE_NETHER);
#endif
if (isNetherRack)
{
return EDhApiBlockMaterial.NETHER_STONE;
}
else if (lowercaseSerialString.contains("stone")
//endregion
//=============//
// misc/simple //
//=============//
//region
if (lowercaseSerialString.contains("snow"))
{
return EDhApiBlockMaterial.SNOW;
}
if (lowercaseSerialString.contains("sand"))
{
return EDhApiBlockMaterial.SAND;
}
if (lowercaseSerialString.contains("terracotta"))
{
return EDhApiBlockMaterial.TERRACOTTA;
}
if (lowercaseSerialString.contains("stone")
|| lowercaseSerialString.contains("ore"))
{
return EDhApiBlockMaterial.STONE;
}
else if (blockState.getLightEmission() > 0)
if (getLightEmission(blockState) > 0)
{
return EDhApiBlockMaterial.ILLUMINATED;
}
else
{
return EDhApiBlockMaterial.UNKNOWN;
}
//endregion
return EDhApiBlockMaterial.UNKNOWN;
}
private static int calculateOpacity(
@Nullable BlockState blockState,
boolean isAir, boolean isLiquid
)
#if MC_VER <= MC_1_12_2
private static int calculateOpacity(@Nullable IBlockState blockState, boolean isAir, boolean isLiquid)
#else
private static int calculateOpacity(@Nullable BlockState blockState, boolean isAir, boolean isLiquid)
#endif
{
// get block properties (defaults to the values used by air)
boolean canOcclude = getCanOcclude(blockState);
@@ -556,24 +816,40 @@ public class BlockStateWrapper implements IBlockStateWrapper
return opacity;
}
#if MC_VER <= MC_1_12_2
private static boolean getCanOcclude(@Nullable IBlockState blockState)
#else
private static boolean getCanOcclude(@Nullable BlockState blockState)
#endif
{
// defaults to the value used by air
boolean canOcclude = false;
if (blockState != null)
{
#if MC_VER <= MC_1_12_2
canOcclude = blockState.getMaterial().isSolid();
#else
canOcclude = blockState.canOcclude();
#endif
}
return canOcclude;
}
#if MC_VER <= MC_1_12_2
private static boolean getPropagatesSkyLightDown(@Nullable IBlockState blockState)
#else
private static boolean getPropagatesSkyLightDown(@Nullable BlockState blockState)
#endif
{
// defaults to the value used by air
boolean propagatesSkyLightDown = true;
if (blockState != null)
{
#if MC_VER < MC_1_21_3
#if MC_VER <= MC_1_12_2
propagatesSkyLightDown = blockState.getBlock().getLightOpacity(blockState) == 0;
#elif MC_VER < MC_1_21_3
propagatesSkyLightDown = blockState.propagatesSkylightDown(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
#else
propagatesSkyLightDown = blockState.propagatesSkylightDown();
@@ -633,8 +909,10 @@ public class BlockStateWrapper implements IBlockStateWrapper
return waterSurfaceReplacementBlocks;
}
ObjectOpenHashSet<String> baseIgnoredBlock = new ObjectOpenHashSet<>();
waterSurfaceReplacementBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.waterSurfaceBlockReplacementCsv, baseIgnoredBlock, levelWrapper);
ObjectOpenHashSet<String> baseIgnoredBlockResourceSet = new ObjectOpenHashSet<>();
waterSurfaceReplacementBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.waterSurfaceBlockReplacementCsv, baseIgnoredBlockResourceSet, levelWrapper);
waterSubsurfaceReplacementBlocks.remove(AIR);
return waterSurfaceReplacementBlocks;
}
public static ObjectOpenHashSet<IBlockStateWrapper> getWaterSubsurfaceReplacementBlocks(ILevelWrapper levelWrapper)
@@ -645,8 +923,12 @@ public class BlockStateWrapper implements IBlockStateWrapper
return waterSubsurfaceReplacementBlocks;
}
ObjectOpenHashSet<String> baseIgnoredBlock = new ObjectOpenHashSet<>();
waterSubsurfaceReplacementBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.waterSubSurfaceBlockReplacementCsv, baseIgnoredBlock, levelWrapper);
ObjectOpenHashSet<String> baseIgnoredBlockResourceSet = new ObjectOpenHashSet<>();
waterSubsurfaceReplacementBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.waterSubSurfaceBlockReplacementCsv, baseIgnoredBlockResourceSet, levelWrapper);
// air will be present if any invalid resource locations are present
// but we don't want to replace air with water, that'll cause monoliths
waterSubsurfaceReplacementBlocks.remove(AIR);
return waterSubsurfaceReplacementBlocks;
}
public static IBlockStateWrapper getWaterBlockStateWrapper(ILevelWrapper levelWrapper)
@@ -714,8 +996,17 @@ public class BlockStateWrapper implements IBlockStateWrapper
if (defaultBlockStateToIgnore != AIR)
{
// add all possible blockstates (to account for light blocks with different light values and such)
#if MC_VER <= MC_1_12_2
List<IBlockState> blockStatesToIgnore = defaultBlockStateToIgnore.blockState.getBlock().getBlockState().getValidStates();
#else
List<BlockState> blockStatesToIgnore = defaultBlockStateToIgnore.blockState.getBlock().getStateDefinition().getPossibleStates();
#endif
#if MC_VER <= MC_1_12_2
for (IBlockState blockState : blockStatesToIgnore)
#else
for (BlockState blockState : blockStatesToIgnore)
#endif
{
BlockStateWrapper newBlockToIgnore = fromBlockState(blockState, levelWrapper);
blockStateWrappers.add(newBlockToIgnore);
@@ -762,7 +1053,25 @@ public class BlockStateWrapper implements IBlockStateWrapper
public int getOpacity() { return this.opacity; }
@Override
public int getLightEmission() { return (this.blockState != null) ? this.blockState.getLightEmission() : 0; }
public int getLightEmission() { return getLightEmission(this.blockState); }
#if MC_VER <= MC_1_12_2
public static int getLightEmission(IBlockState blockState)
#else
public static int getLightEmission(BlockState blockState)
#endif
{
if (blockState == null)
{
return 0;
}
#if MC_VER <= MC_1_12_2
return blockState.getLightValue();
#else
return blockState.getLightEmission();
#endif
}
@Override
public String getSerialString() { return this.serialString; }
@@ -772,7 +1081,23 @@ public class BlockStateWrapper implements IBlockStateWrapper
@Override
public boolean isAir() { return isAir(this.blockState); }
public static boolean isAir(BlockState blockState) { return blockState == null || blockState.isAir(); }
#if MC_VER <= MC_1_12_2
public static boolean isAir(IBlockState blockState)
#else
public static boolean isAir(BlockState blockState)
#endif
{
if (blockState == null)
{
return true;
}
#if MC_VER <= MC_1_12_2
return blockState.getBlock() == Blocks.AIR;
#else
return blockState.isAir();
#endif
}
@Override
public boolean isSolid() { return this.isSolid; }
@@ -806,7 +1131,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
//=======================//
//region
#if MC_VER <= MC_1_12_2
private static String serialize(IBlockState blockState, ILevelWrapper levelWrapper)
#else
private static String serialize(BlockState blockState, ILevelWrapper levelWrapper)
#endif
{
if (blockState == null)
{
@@ -828,7 +1157,9 @@ public class BlockStateWrapper implements IBlockStateWrapper
Identifier resourceLocation;
#endif
#if MC_VER <= MC_1_17_1
#if MC_VER <= MC_1_12_2
resourceLocation = blockState.getBlock().getRegistryName();
#elif MC_VER <= MC_1_17_1
resourceLocation = Registry.BLOCK.getKey(blockState.getBlock());
#elif MC_VER <= MC_1_19_2
resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(blockState.getBlock());
@@ -927,7 +1258,9 @@ public class BlockStateWrapper implements IBlockStateWrapper
#endif
Block block;
#if MC_VER <= MC_1_17_1
#if MC_VER <= MC_1_12_2
block = Block.REGISTRY.getObject(resourceLocation);
#elif MC_VER <= MC_1_17_1
block = Registry.BLOCK.get(resourceLocation);
#elif MC_VER <= MC_1_19_2
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
@@ -956,11 +1289,24 @@ public class BlockStateWrapper implements IBlockStateWrapper
// attempt to find the blockstate from all possibilities
#if MC_VER <= MC_1_12_2
IBlockState foundState = null;
#else
BlockState foundState = null;
#endif
if (blockStatePropertiesString != null)
{
#if MC_VER <= MC_1_12_2
List<IBlockState> possibleStateList = block.getBlockState().getValidStates();
#else
List<BlockState> possibleStateList = block.getStateDefinition().getPossibleStates();
#endif
#if MC_VER <= MC_1_12_2
for (IBlockState possibleState : possibleStateList)
#else
for (BlockState possibleState : possibleStateList)
#endif
{
String possibleStatePropertiesString = serializeBlockStateProperties(possibleState);
if (possibleStatePropertiesString.equals(blockStatePropertiesString))
@@ -984,7 +1330,12 @@ public class BlockStateWrapper implements IBlockStateWrapper
}
}
foundState = block.defaultBlockState();
#if MC_VER <= MC_1_12_2
foundState = block.getDefaultState();
#else
foundState = block.defaultBlockState();
#endif
}
foundWrapper = fromBlockState(foundState, levelWrapper);
@@ -1000,30 +1351,53 @@ public class BlockStateWrapper implements IBlockStateWrapper
// put if absent in case two threads deserialize at the same time
// unfortunately we can't put everything in a computeIfAbsent() since we also throw exceptions
WRAPPER_BY_RESOURCE_LOCATION.putIfAbsent(finalResourceStateString, foundWrapper);
if (foundWrapper != AIR)
{
WRAPPER_BY_BLOCK_STATE.putIfAbsent(foundWrapper.blockState, foundWrapper);
}
}
}
/** used to compare and save BlockStates based on their properties */
#if MC_VER <= MC_1_12_2
private static String serializeBlockStateProperties(IBlockState blockState)
#else
private static String serializeBlockStateProperties(BlockState blockState)
#endif
{
// get the property list for this block (doesn't contain this block state's values, just the names and possible values)
java.util.Collection<net.minecraft.world.level.block.state.properties.Property<?>> blockPropertyCollection = blockState.getProperties();
#if MC_VER <= MC_1_12_2
java.util.Collection<IProperty<?>> blockPropertyCollection = blockState.getPropertyKeys();
List<IProperty<?>> sortedBlockPropteryList = new ArrayList<>(blockPropertyCollection);
#else
java.util.Collection<net.minecraft.world.level.block.state.properties.Property<?>> blockPropertyCollection = blockState.getProperties();;
List<net.minecraft.world.level.block.state.properties.Property<?>> sortedBlockPropteryList = new ArrayList<>(blockPropertyCollection);
#endif
// alphabetically sort the list so they are always in the same order
List<net.minecraft.world.level.block.state.properties.Property<?>> sortedBlockPropteryList = new ArrayList<>(blockPropertyCollection);
sortedBlockPropteryList.sort((a, b) -> a.getName().compareTo(b.getName()));
StringBuilder stringBuilder = new StringBuilder();
#if MC_VER <= MC_1_12_2
for (IProperty<?> property : sortedBlockPropteryList)
#else
for (net.minecraft.world.level.block.state.properties.Property<?> property : sortedBlockPropteryList)
#endif
{
String propertyName = property.getName();
String value = "NULL";
#if MC_VER <= MC_1_12_2
value = blockState.getValue(property).toString();
#else
if (blockState.hasProperty(property))
{
value = blockState.getValue(property).toString();
}
#endif
stringBuilder.append("{");
stringBuilder.append(propertyName).append(RESOURCE_LOCATION_SEPARATOR).append(value);
@@ -32,22 +32,31 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapp
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
#if MC_VER <= MC_1_12_2
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.block.BlockRotatedPillar;
import net.minecraft.block.*;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.renderer.color.BlockColors;
import net.minecraft.util.math.BlockPos;
#else
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.state.BlockState;
import com.seibel.distanthorizons.core.logging.DhLogger;
import net.minecraft.world.level.block.state.properties.SlabType;
#endif
import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.*;
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
@@ -64,19 +73,32 @@ import net.minecraft.client.color.block.BlockTintSource;
/**
* This stores and calculates the colors
* the given {@link BlockState} should have based
* the given BlockState should have based
* on the given {@link IClientLevelWrapper}.
*
*
* @see ColorUtil
*/
public class ClientBlockStateColorCache
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
#if MC_VER <= MC_1_12_2
private static final Minecraft MC = Minecraft.getMinecraft();
#else
private static final Minecraft MC = Minecraft.getInstance();
#endif
#if MC_VER <= MC_1_12_2
#else
private static final HashSet<BlockState> BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>();
#endif
#if MC_VER <= MC_1_12_2
private static final HashSet<IBlockState> BROKEN_BLOCK_STATES = new HashSet<>();
#else
private static final HashSet<BlockState> BROKEN_BLOCK_STATES = new HashSet<>();
#endif
/**
* Methods using MC's "RandomSource" object aren't thread safe <br>
@@ -88,18 +110,33 @@ public class ClientBlockStateColorCache
*/
private static final ReentrantLock RESOLVE_LOCK = new ReentrantLock();
public static final int INVALID_COLOR = -1;
/** This is the order each direction on a block is processed when attempting to get the texture/color */
#if MC_VER <= MC_1_12_2
private static final @Nullable EnumFacing[] COLOR_RESOLUTION_DIRECTION_ORDER =
{
EnumFacing.UP,
null, // null represents "unculled" faces, IE the top of farmland
EnumFacing.NORTH,
EnumFacing.EAST,
EnumFacing.WEST,
EnumFacing.SOUTH,
EnumFacing.DOWN
};
#else
private static final @Nullable Direction[] COLOR_RESOLUTION_DIRECTION_ORDER =
{
{
Direction.UP,
null, // null represents "unculled" faces, IE the top of farmland
Direction.NORTH,
Direction.EAST,
Direction.WEST,
Direction.SOUTH,
Direction.DOWN
Direction.NORTH,
Direction.EAST,
Direction.WEST,
Direction.SOUTH,
Direction.DOWN
};
#endif
private static final int FLOWER_COLOR_SCALE = 5;
@@ -113,7 +150,11 @@ public class ClientBlockStateColorCache
#endif
private final IClientLevelWrapper clientLevelWrapper;
#if MC_VER <= MC_1_12_2
private final IBlockState blockState;
#else
private final BlockState blockState;
#endif
private final BlockStateWrapper blockStateWrapper;
private boolean isColorResolved = false;
@@ -191,8 +232,10 @@ public class ClientBlockStateColorCache
};
// these are threadlocals since AbstractDhTintGetter use local variables to handle color queries
#if MC_VER > MC_1_12_2
private static final ThreadLocal<TintWithoutLevelOverrider> TintWithoutLevelOverrideGetter = ThreadLocal.withInitial(TintWithoutLevelOverrider::new);
private static final ThreadLocal<TintGetterOverride> TintOverrideGetter = ThreadLocal.withInitial(TintGetterOverride::new);
#endif
private static final ThreadLocal<DhApiBlockColorOverrideEvent.EventParam> ColorOverrideEventParamGetter = ThreadLocal.withInitial(DhApiBlockColorOverrideEvent.EventParam::new);
//endregion
@@ -204,7 +247,11 @@ public class ClientBlockStateColorCache
//=============//
//region
#if MC_VER <= MC_1_12_2
public ClientBlockStateColorCache(IBlockState blockState, IClientLevelWrapper clientLevelWrapper)
#else
public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper clientLevelWrapper)
#endif
{
this.blockState = blockState;
this.blockStateWrapper = BlockStateWrapper.fromBlockState(blockState, clientLevelWrapper);
@@ -220,6 +267,7 @@ public class ClientBlockStateColorCache
//===================//
// color calculation //
//===================//
//region
private void resolveColors()
{
@@ -233,17 +281,54 @@ public class ClientBlockStateColorCache
// getQuads() isn't thread safe so we need to put this logic in a lock
RESOLVE_LOCK.lock();
if (this.blockState.getFluidState().isEmpty())
#if MC_VER <= MC_1_12_2
if (this.blockState.getRenderType() == EnumBlockRenderType.ENTITYBLOCK_ANIMATED)
{
this.needPostTinting = false;
this.tintIndex = 0;
this.baseColor = ColorUtil.argbToInt(255,
this.blockStateWrapper.getMapColor().getRed(),
this.blockStateWrapper.getMapColor().getGreen(),
this.blockStateWrapper.getMapColor().getBlue());
this.isColorResolved = true;
return;
}
#endif
if (!this.blockStateWrapper.isLiquid())
{
// look for the first non-empty direction
List<BakedQuad> quads = null;
for (Direction direction : COLOR_RESOLUTION_DIRECTION_ORDER)
#if MC_VER <= MC_1_12_2
EnumFacing direction;
#else
Direction direction;
#endif
for (int i = 0; i < COLOR_RESOLUTION_DIRECTION_ORDER.length; i++)
{
quads = this.getQuadsForDirection(direction);
if (quads != null && !quads.isEmpty()
direction = COLOR_RESOLUTION_DIRECTION_ORDER[i];
try
{
quads = this.getQuadsForDirection(direction);
}
catch (Exception ignore)
{
// failing to get quads can happen in the block is invalid
// (i.e. AIR is somehow passed in)
}
if (quads != null
&& !quads.isEmpty()
&& !(
#if MC_VER <= MC_1_12_2
this.blockState.getBlock() instanceof BlockRotatedPillar
&& direction == EnumFacing.UP
#else
this.blockState.getBlock() instanceof RotatedPillarBlock
&& direction == Direction.UP
#endif
)
)
{
@@ -253,46 +338,72 @@ public class ClientBlockStateColorCache
if (quads == null || quads.isEmpty())
{
quads = this.getUnculledQuads();
try
{
quads = this.getUnculledQuads();
}
catch (Exception ignore)
{
// failing to get quads can happen in the block is invalid
// (i.e. AIR is somehow passed in)
}
}
if (quads != null
&& !quads.isEmpty()
&& quads.get(0) != null)
{
BakedQuad firstQuad = quads.get(0);
try
{
BakedQuad firstQuad = quads.get(0);
#if MC_VER <= MC_1_12_2
this.needPostTinting = firstQuad.hasTintIndex();
#elif MC_VER <= MC_1_21_11
this.needPostTinting = firstQuad.isTinted();
#else
this.needPostTinting = firstQuad.materialInfo().isTinted();
#endif
#if MC_VER <= MC_1_21_11
this.needPostTinting = firstQuad.isTinted();
#else
this.needPostTinting = firstQuad.materialInfo().isTinted();
#endif
#if MC_VER <= MC_1_21_4
this.tintIndex = firstQuad.getTintIndex();
#elif MC_VER <= MC_1_21_11
this.tintIndex = firstQuad.tintIndex();
#else
this.tintIndex = firstQuad.materialInfo().tintIndex();
#endif
#if MC_VER < MC_1_17_1
this.baseColor = calculateColorFromTexture(
firstQuad.sprite,
EColorMode.getColorMode(this.blockState.getBlock()));
#elif MC_VER < MC_1_21_5
this.baseColor = calculateColorFromTexture(
firstQuad.getSprite(),
EColorMode.getColorMode(this.blockState.getBlock()));
#elif MC_VER <= MC_1_21_11
this.baseColor = calculateColorFromTexture(
firstQuad.sprite(),
EColorMode.getColorMode(this.blockState.getBlock()));
#else
this.baseColor = calculateColorFromTexture(
firstQuad.materialInfo().sprite(),
EColorMode.getColorMode(this.blockState.getBlock()));
#endif
#if MC_VER <= MC_1_21_4
this.tintIndex = firstQuad.getTintIndex();
#elif MC_VER <= MC_1_21_11
this.tintIndex = firstQuad.tintIndex();
#else
this.tintIndex = firstQuad.materialInfo().tintIndex();
#endif
#if MC_VER < MC_1_17_1 && MC_VER > MC_1_12_2
this.baseColor = calculateColorFromTexture(
firstQuad.sprite,
EColorMode.getColorMode(this.blockState.getBlock()));
#elif MC_VER < MC_1_21_5
this.baseColor = calculateColorFromTexture(
firstQuad.getSprite(),
EColorMode.getColorMode(this.blockState.getBlock()));
#elif MC_VER <= MC_1_21_11
this.baseColor = calculateColorFromTexture(
firstQuad.sprite(),
EColorMode.getColorMode(this.blockState.getBlock()));
#else
this.baseColor = calculateColorFromTexture(
firstQuad.materialInfo().sprite(),
EColorMode.getColorMode(this.blockState.getBlock()));
#endif
}
catch (Exception e)
{
// Shouldn't normally happen, but there was at least
// one report of MC's texture being un-loaded
// which prevented us from getting the texture.
// So we should have some basic backup logic.
LOGGER.warn("Failed to get texture color for block ["+this.blockStateWrapper.getSerialString()+"] due to: ["+e.getMessage()+"], falling back to particle color.");
this.needPostTinting = false;
this.tintIndex = 0;
this.baseColor = this.getParticleIconColor();
}
}
else
{
@@ -313,6 +424,23 @@ public class ClientBlockStateColorCache
this.isColorResolved = true;
}
catch (Exception resolveError)
{
LOGGER.warn("Failed to get color for block ["+this.blockStateWrapper.getSerialString()+"], error: ["+resolveError.getMessage()+"]. Attempting to use particle icon color...", resolveError);
this.needPostTinting = true;
this.tintIndex = 0;
try
{
this.baseColor = this.getParticleIconColor();
}
catch (Exception getParticleIconError)
{
LOGGER.warn("Failed to get particle icon color for block ["+this.blockStateWrapper.getSerialString()+"], error: ["+getParticleIconError.getMessage()+"], block will render as hot pink.", getParticleIconError);
this.baseColor = ColorUtil.HOT_PINK;
}
}
finally
{
RESOLVE_LOCK.unlock();
@@ -320,22 +448,49 @@ public class ClientBlockStateColorCache
}
@Nullable
private List<BakedQuad> getUnculledQuads() { return this.getQuadsForDirection(null); }
private List<BakedQuad> getUnculledQuads() throws Exception { return this.getQuadsForDirection(null); }
/**
* throws Exception is to document that rarely MC will throw errors if this method
* is called on the wrong block (even though in that case it should just return null).
*/
@Nullable
private List<BakedQuad> getQuadsForDirection(@Nullable Direction direction)
#if MC_VER <= MC_1_12_2
private List<BakedQuad> getQuadsForDirection(@Nullable EnumFacing direction) throws Exception
#else
private List<BakedQuad> getQuadsForDirection(@Nullable Direction direction) throws Exception
#endif
{
#if MC_VER <= MC_1_12_2
IBlockState effectiveBlockState = this.blockState;
#else
BlockState effectiveBlockState = this.blockState;
#endif
// if this block is a slab, use it's double variant so we can get the top face,
// otherwise the color will use the side, which isn't as accurate
#if MC_VER <= MC_1_12_2
if (this.blockState.getBlock() instanceof BlockSlab && !((BlockSlab) this.blockState.getBlock()).isDouble())
{
effectiveBlockState = this.blockState.withProperty(BlockSlab.HALF, BlockSlab.EnumBlockHalf.TOP);
}
#else
if (this.blockState.getBlock() instanceof SlabBlock)
{
effectiveBlockState = this.blockState.setValue( SlabBlock.TYPE, SlabType.DOUBLE );
}
#endif
List<BakedQuad> quads;
#if MC_VER < MC_1_21_5
#if MC_VER <= MC_1_12_2
try {
quads = MC.getBlockRendererDispatcher().getModelForState(effectiveBlockState).getQuads(effectiveBlockState, direction, RANDOM.nextLong());
}
catch (Exception e)
{
quads = Collections.emptyList();
}
#elif MC_VER < MC_1_21_5
quads = MC.getModelManager().getBlockModelShaper().
getBlockModel(effectiveBlockState).getQuads(effectiveBlockState, direction, RANDOM);
#elif MC_VER <= MC_1_21_11
@@ -392,29 +547,29 @@ public class ClientBlockStateColorCache
//_ OpenGL RGBA format Java Order: 0xAA BB GG RR
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
#if MC_VER <= MC_1_12_2
int b = (tempColor & 0x000000FF);
int g = (tempColor & 0x0000FF00) >>> 8;
int r = (tempColor & 0x00FF0000) >>> 16;
int a = (tempColor & 0xFF000000) >>> 24;
#else
int r = (tempColor & 0x000000FF);
int g = (tempColor & 0x0000FF00) >>> 8;
int b = (tempColor & 0x00FF0000) >>> 16;
int a = (tempColor & 0xFF000000) >>> 24;
#endif
int scale = 1;
if (colorMode == EColorMode.Leaves)
{
//switch (//FIXME add config option)
// case BLACK:
// a = 255; //simulate black background of fast leaves
// break;
// case IGNORE:
if (a == 0) {
continue; //same long grass
}
else
{
a = 255; //just in case there are semi transparent pixels
}
// break;
// case TRANSPARENT:
// break; //do nothing, let it count towards transparency
if (a == 0)
{
continue; //same long grass
}
else
{
a = 255; //just in case there are semi transparent pixels
}
}
else if (a == 0 && colorMode != EColorMode.Glass)
{
@@ -460,7 +615,9 @@ public class ClientBlockStateColorCache
}
private static int getTextureWidth(TextureAtlasSprite texture)
{
#if MC_VER < MC_1_19_4
#if MC_VER <= MC_1_12_2
return texture.getIconWidth();
#elif MC_VER < MC_1_19_4
return texture.getWidth();
#else
return texture.contents().width();
@@ -468,7 +625,9 @@ public class ClientBlockStateColorCache
}
private static int getTextureHeight(TextureAtlasSprite texture)
{
#if MC_VER < MC_1_19_4
#if MC_VER <= MC_1_12_2
return texture.getIconHeight();
#elif MC_VER < MC_1_19_4
return texture.getHeight();
#else
return texture.contents().height();
@@ -501,8 +660,19 @@ public class ClientBlockStateColorCache
private int getParticleIconColor()
{
// Air can be null which will cause issues below,
// just use a static color, it shouldn't be rendered anyway.
// This is just to capture a rare bug state where we attempt
// to get air's color.
if (BlockStateWrapper.isAir(this.blockState))
{
return ColorUtil.INVISIBLE;
}
return calculateColorFromTexture(
#if MC_VER <= MC_1_21_11
#if MC_VER <= MC_1_12_2
Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelShapes().getTexture(this.blockState),
#elif MC_VER <= MC_1_21_11
Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState),
#else
Minecraft.getInstance().getModelManager().getBlockStateModelSet().get(this.blockState).particleMaterial().sprite(),
@@ -510,16 +680,22 @@ public class ClientBlockStateColorCache
EColorMode.getColorMode(this.blockState.getBlock()));
}
//endregion
//===============//
// public getter //
//===============//
//region
public int getColor(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, DhBlockPos blockPos)
public int getColor(
BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, DhBlockPos blockPos,
boolean allowApiOverride)
{
// only get the tint if the block needs to be tinted
int tintColor = AbstractDhTintGetter.INVALID_COLOR;
int tintColor = ClientBlockStateColorCache.INVALID_COLOR;
if (this.needPostTinting)
{
// don't try tinting blocks that don't support our method of tint getting
@@ -532,28 +708,62 @@ public class ClientBlockStateColorCache
// attempt to get the tint
try
{
#if MC_VER <= MC_1_12_2
// 1.12.2 doesn't have BlockAndTintGetter -> get tintColor from biome
WorldClient world = (WorldClient) this.clientLevelWrapper.getWrappedMcObject();
BlockPos mcPos = new BlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ());
Block block = this.blockState.getBlock();
if (block instanceof BlockGrass
|| block instanceof BlockBush)
{
tintColor = biomeWrapper.biome.getGrassColorAtPos(mcPos);
}
else if (block instanceof BlockLeaves)
{
tintColor = biomeWrapper.biome.getFoliageColorAtPos(mcPos);
}
else if (block instanceof BlockLiquid) // We don't want lava to fall into the else block
{
if(block == Blocks.WATER
|| block == Blocks.FLOWING_WATER)
{
tintColor = biomeWrapper.biome.getWaterColor();
}
}
else
{
BlockColors blockColors = Minecraft.getMinecraft().getBlockColors();
tintColor = blockColors.colorMultiplier(blockState, world, mcPos, this.tintIndex);
if (tintColor == ClientBlockStateColorCache.INVALID_COLOR)
{
tintColor = blockColors.getColor(blockState, world, mcPos);
}
}
#else
// try to use the fast tint getter logic first
if (!BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
{
try
{
{
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));
if (tintColor == AbstractDhTintGetter.INVALID_COLOR)
if (tintColor == ClientBlockStateColorCache.INVALID_COLOR)
{
// one or more tint values weren't calculated,
// we need MC's color resolver
#if MC_VER <= MC_1_21_11
tintColor = Minecraft.getInstance()
#if MC_VER <= MC_1_21_11
tintColor = Minecraft.getInstance()
.getBlockColors()
.getColor(this.blockState,
tintOverride, // tintOverride will save the result of this query to speed up future queries
McObjectConverter.Convert(blockPos),
this.tintIndex);
#else
#else
BlockTintSource tintSource = Minecraft.getInstance()
.getBlockColors()
.getTintSource(this.blockState, this.tintIndex);
@@ -564,18 +774,12 @@ public class ClientBlockStateColorCache
{
BlockPos mcPos = McObjectConverter.Convert(blockPos);
tintColor = tintSource.colorInWorld(this.blockState, tintOverride, mcPos);
if (tintColor == -1)
if (tintColor == ClientBlockStateColorCache.INVALID_COLOR)
{
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
@@ -585,44 +789,47 @@ public class ClientBlockStateColorCache
}
catch (Exception e)
{
#if MC_VER <= MC_1_21_11
// 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);
BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState);
#else
#if MC_VER <= MC_1_21_11
// 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);
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
#endif
}
}
#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
if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
{
// the level shouldn't be used all the time due to it breaking some blocks tinting
// specifically oceans don't render correctly
TintGetterOverride tintOverride = TintOverrideGetter.get();
tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper);
tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos));
if (tintColor == AbstractDhTintGetter.INVALID_COLOR)
#if MC_VER <= MC_1_21_11 && MC_VER > MC_1_12_2
// use the level logic only if requested
if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
{
tintColor = Minecraft.getInstance()
.getBlockColors()
.getColor(this.blockState,
tintOverride,
McObjectConverter.Convert(blockPos),
this.tintIndex);
// the level shouldn't be used all the time due to it breaking some blocks tinting
// specifically oceans don't render correctly
TintGetterOverride tintOverride = TintOverrideGetter.get();
tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper);
tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos));
if (tintColor == ClientBlockStateColorCache.INVALID_COLOR)
{
tintColor = Minecraft.getInstance()
.getBlockColors()
.getColor(this.blockState,
tintOverride,
McObjectConverter.Convert(blockPos),
this.tintIndex);
}
}
}
#endif
#endif
}
catch (Exception e)
{
@@ -637,7 +844,7 @@ public class ClientBlockStateColorCache
int returnColor;
if (tintColor != AbstractDhTintGetter.INVALID_COLOR)
if (tintColor != ClientBlockStateColorCache.INVALID_COLOR)
{
returnColor = ColorUtil.multiplyARGBwithRGB(this.baseColor, tintColor);
}
@@ -648,14 +855,17 @@ public class ClientBlockStateColorCache
}
// only fire an API event if needed
// (this is done to reduce GC pressure and speed up color getting)
if (this.blockStateWrapper.allowApiColorOverride())
// only fire the API event if allowed
// (done to prevent infinite loops if called during by another color resolution event)
if (allowApiOverride
// if the API event is requested
// (this is done to reduce GC pressure and speed up color getting)
&& this.blockStateWrapper.allowApiColorOverride())
{
DhApiBlockColorOverrideEvent.EventParam eventParam = ColorOverrideEventParamGetter.get();
eventParam.update(
this.clientLevelWrapper,
this.blockStateWrapper, returnColor,
this.clientLevelWrapper, fullDataSource,
this.blockStateWrapper, biomeWrapper, returnColor,
blockPos.getX(), blockPos.getY(), blockPos.getZ()
);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBlockColorOverrideEvent.class, eventParam);
@@ -667,6 +877,25 @@ public class ClientBlockStateColorCache
return returnColor;
}
//endregion
//=========//
// cleanup //
//=========//
//region
public static void clearCachedTints()
{
#if MC_VER <= MC_1_12_2
#else
AbstractDhTintGetter.clear();
#endif
}
//endregion
//================//
@@ -684,14 +913,54 @@ public class ClientBlockStateColorCache
static EColorMode getColorMode(Block block)
{
if (block instanceof LeavesBlock)
//========//
// leaves //
//========//
//region
boolean isLeavesBlock;
#if MC_VER <= MC_1_12_2
isLeavesBlock = block instanceof BlockLeaves;
#else
isLeavesBlock = block instanceof LeavesBlock;
#endif
if (isLeavesBlock)
{
return Leaves;
}
if (block instanceof FlowerBlock)
//endregion
//========//
// flower //
//========//
//region
boolean isFlowerBlock;
#if MC_VER <= MC_1_12_2
isFlowerBlock = block instanceof BlockFlower;
#else
isFlowerBlock = block instanceof FlowerBlock;
#endif
if (isFlowerBlock)
{
return Flower;
}
//endregion
//=============//
// misc/simple //
//=============//
//region
if (block.toString().contains("glass"))
{
return Glass;
@@ -700,6 +969,11 @@ public class ClientBlockStateColorCache
{
return Chisel;
}
//endregion
return Default;
}
}
@@ -38,7 +38,10 @@ public class TextureAtlasSpriteWrapper
{
public static int getPixelRGBA(TextureAtlasSprite sprite, int frameIndex, int x, int y)
{
#if MC_VER < MC_1_17_1
#if MC_VER <= MC_1_12_2
int[][] frameData = sprite.getFrameTextureData(frameIndex);
return frameData[0][y * sprite.getIconWidth() + x];
#elif MC_VER < MC_1_17_1
return sprite.mainImage[0].getPixelRGBA(
x + sprite.framesX[frameIndex] * sprite.getWidth(),
y + sprite.framesY[frameIndex] * sprite.getHeight());
@@ -18,7 +18,7 @@
*/
package com.seibel.distanthorizons.common.wrappers.block;
#if MC_VER > MC_1_12_2
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.core.BlockPos;
@@ -189,3 +189,4 @@ public class TintGetterOverride extends AbstractDhTintGetter
}
#endif
@@ -18,7 +18,7 @@
*/
package com.seibel.distanthorizons.common.wrappers.block;
#if MC_VER > MC_1_12_2
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.LevelReader;
@@ -109,3 +109,4 @@ public class TintWithoutLevelOverrider extends AbstractDhTintGetter
}
#endif
@@ -31,12 +31,19 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IMutableBlockPosWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
#if MC_VER <= MC_1_12_2
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
#else
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.levelgen.Heightmap;
#endif
import com.seibel.distanthorizons.core.logging.DhLogger;
@@ -67,9 +74,10 @@ import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.LevelChunkSection;
#endif
#if MC_VER <= MC_1_20_4
#if MC_VER <= MC_1_12_2
#elif MC_VER <= MC_1_20_4
import net.minecraft.world.level.chunk.ChunkStatus;
#else
#elif MC_VER > MC_1_12_2
import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif
@@ -86,8 +94,12 @@ public class ChunkWrapper implements IChunkWrapper
private static boolean heightmapThreadWarningLogged = false;
#if MC_VER <= MC_1_12_2
private final Chunk chunk;
#else
private final ChunkAccess chunk;
#endif
private final DhChunkPos chunkPos;
private final ILevelWrapper wrappedLevel;
@@ -112,13 +124,17 @@ public class ChunkWrapper implements IChunkWrapper
//=============//
// constructor //
//=============//
//region
/**
* Note: this constructor should be very
* fast since it will be called frequently on the MC
* server thread and a slow method will cause server lag.
*/
#if MC_VER <= MC_1_12_2
public ChunkWrapper(Chunk chunk, ILevelWrapper wrappedLevel)
#else
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel)
#endif
{
this.chunk = chunk;
this.wrappedLevel = wrappedLevel;
@@ -133,15 +149,22 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public ChunkWrapper copy() { return new ChunkWrapper(this.chunk, this.wrappedLevel); }
//endregion
//=========//
// getters //
//=========//
//region
@Override
public int getHeight() { return getHeight(this.chunk); }
#if MC_VER <= MC_1_12_2
public static int getHeight(Chunk chunk)
#else
public static int getHeight(ChunkAccess chunk)
#endif
{
#if MC_VER < MC_1_17_1
return 255;
@@ -152,7 +175,11 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public int getInclusiveMinBuildHeight() { return getInclusiveMinBuildHeight(this.chunk); }
#if MC_VER <= MC_1_12_2
public static int getInclusiveMinBuildHeight(Chunk chunk)
#else
public static int getInclusiveMinBuildHeight(ChunkAccess chunk)
#endif
{
#if MC_VER < MC_1_17_1
return 0;
@@ -165,9 +192,15 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public int getExclusiveMaxBuildHeight() { return getExclusiveMaxBuildHeight(this.chunk); }
#if MC_VER <= MC_1_12_2
public static int getExclusiveMaxBuildHeight(Chunk chunk)
#else
public static int getExclusiveMaxBuildHeight(ChunkAccess chunk)
#endif
{
#if MC_VER < MC_1_21_3
#if MC_VER <= MC_1_12_2
return 256;
#elif MC_VER < MC_1_21_3
return chunk.getMaxBuildHeight();
#else
// +1 since Minecraft made the max value inclusive
@@ -188,7 +221,11 @@ public class ChunkWrapper implements IChunkWrapper
this.minNonEmptyHeight = this.getInclusiveMinBuildHeight();
// determine the lowest empty section (bottom up)
#if MC_VER <= MC_1_12_2
ExtendedBlockStorage[] sections = this.chunk.getBlockStorageArray();
#else
LevelChunkSection[] sections = this.chunk.getSections();
#endif
for (int index = 0; index < sections.length; index++)
{
if (sections[index] == null)
@@ -220,7 +257,11 @@ public class ChunkWrapper implements IChunkWrapper
this.maxNonEmptyHeight = this.getExclusiveMaxBuildHeight();
// determine the highest empty section (top down)
#if MC_VER <= MC_1_12_2
ExtendedBlockStorage[] sections = this.chunk.getBlockStorageArray();
#else
LevelChunkSection[] sections = this.chunk.getSections();
#endif
for (int index = sections.length-1; index >= 0; index--)
{
// update at each position to fix using the max height if the chunk is empty
@@ -240,11 +281,13 @@ public class ChunkWrapper implements IChunkWrapper
return this.maxNonEmptyHeight;
}
#if MC_VER <= MC_1_12_2
private static boolean isChunkSectionEmpty(ExtendedBlockStorage section)
#else
private static boolean isChunkSectionEmpty(LevelChunkSection section)
#endif
{
#if MC_VER == MC_1_16_5
return section.isEmpty();
#elif MC_VER == MC_1_17_1
#if MC_VER <= MC_1_17_1
return section.isEmpty();
#else
return section.hasOnlyAir();
@@ -322,7 +365,11 @@ public class ChunkWrapper implements IChunkWrapper
// will be null if we want to use MC heightmaps
if (this.solidHeightMap == null)
{
#if MC_VER <= MC_1_12_2
return this.chunk.getHeightValue(xRel, zRel);
#else
return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE).getFirstAvailable(xRel, zRel);
#endif
}
else
{
@@ -337,19 +384,30 @@ public class ChunkWrapper implements IChunkWrapper
if (this.lightBlockingHeightMap == null)
{
#if MC_VER <= MC_1_12_2
return this.chunk.getHeightValue(xRel, zRel);
#else
return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING).getFirstAvailable(xRel, zRel);
#endif
}
else
{
return this.lightBlockingHeightMap[xRel][zRel];
}
}
}
@Override
public IBiomeWrapper getBiome(int relX, int relY, int relZ)
{
#if MC_VER < MC_1_17_1
#if MC_VER <= MC_1_12_2
BlockPos.MutableBlockPos blockPos = MUTABLE_BLOCK_POS_REF.get();
blockPos.setPos(relX, relY, relZ);
World world = (World) this.wrappedLevel.getWrappedMcObject();
return BiomeWrapper.getBiomeWrapper(this.chunk.getBiome(blockPos, world.getBiomeProvider()), wrappedLevel);
#elif MC_VER < MC_1_17_1
return BiomeWrapper.getBiomeWrapper(this.chunk.getBiomes().getNoiseBiome(
relX >> 2, relY >> 2, relZ >> 2),
this.wrappedLevel);
@@ -357,10 +415,6 @@ public class ChunkWrapper implements IChunkWrapper
return BiomeWrapper.getBiomeWrapper(this.chunk.getBiomes().getNoiseBiome(
QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)),
this.wrappedLevel);
#elif MC_VER < MC_1_18_2
return BiomeWrapper.getBiomeWrapper(this.chunk.getNoiseBiome(
QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)),
this.wrappedLevel);
#else
//Now returns a Holder<Biome> instead of Biome
return BiomeWrapper.getBiomeWrapper(this.chunk.getNoiseBiome(
@@ -376,9 +430,13 @@ public class ChunkWrapper implements IChunkWrapper
BlockPos.MutableBlockPos blockPos = MUTABLE_BLOCK_POS_REF.get();
#if MC_VER <= MC_1_12_2
blockPos.setPos(relX, relY, relZ);
#else
blockPos.setX(relX);
blockPos.setY(relY);
blockPos.setZ(relZ);
#endif
try
{
@@ -401,9 +459,13 @@ public class ChunkWrapper implements IChunkWrapper
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
BlockPos.MutableBlockPos pos = (BlockPos.MutableBlockPos)mcBlockPos.getWrappedMcObject();
#if MC_VER <= MC_1_12_2
pos.setPos(relX, relY, relZ);
#else
pos.setX(relX);
pos.setY(relY);
pos.setZ(relZ);
#endif
try
{
@@ -513,8 +575,14 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public DhChunkPos getChunkPos() { return this.chunkPos; }
public ChunkAccess getChunk() { return this.chunk; }
#if MC_VER <= MC_1_12_2
public Chunk getChunk()
#else
public ChunkAccess getChunk()
#endif
{ return this.chunk; }
#if MC_VER > MC_1_12_2
public void trySetStatus(ChunkStatus status) { trySetStatus(this.getChunk(), status); }
/** does nothing if the chunk object doesn't support setting it's status */
public static void trySetStatus(ChunkAccess chunk, ChunkStatus status)
@@ -538,21 +606,53 @@ public class ChunkWrapper implements IChunkWrapper
return chunk.getPersistedStatus();
#endif
}
#endif
@Override
public int getMaxBlockX() { return this.chunk.getPos().getMaxBlockX(); }
public int getMaxBlockX()
{
#if MC_VER <= MC_1_12_2
return this.chunk.getPos().getXEnd();
#else
return this.chunk.getPos().getMaxBlockX();
#endif
}
@Override
public int getMaxBlockZ() { return this.chunk.getPos().getMaxBlockZ(); }
public int getMaxBlockZ()
{
#if MC_VER <= MC_1_12_2
return this.chunk.getPos().getZEnd();
#else
return this.chunk.getPos().getMaxBlockZ();
#endif
}
@Override
public int getMinBlockX() { return this.chunk.getPos().getMinBlockX(); }
public int getMinBlockX()
{
#if MC_VER <= MC_1_12_2
return this.chunk.getPos().getXStart();
#else
return this.chunk.getPos().getMinBlockX();
#endif
}
@Override
public int getMinBlockZ() { return this.chunk.getPos().getMinBlockZ(); }
public int getMinBlockZ()
{
#if MC_VER <= MC_1_12_2
return this.chunk.getPos().getZStart();
#else
return this.chunk.getPos().getMinBlockZ();
#endif
}
//endregion
//==========//
// lighting //
//==========//
//region
@Override
public void setIsDhSkyLightCorrect(boolean isDhLightCorrect) { this.isDhSkyLightCorrect = isDhLightCorrect; }
@@ -629,8 +729,23 @@ public class ChunkWrapper implements IChunkWrapper
{
this.blockLightPosList = new ArrayList<>();
#if MC_VER < MC_1_20_1
//1.12.2 doesn't store lights we must bruteforce it
#if MC_VER <= MC_1_12_2
for (int x = 0; x < 16; x++)
{
for (int z = 0; z < 16; z++)
{
for (int y = 0; y < 256; y++)
{
IBlockState blockState = this.chunk.getBlockState(x, y, z);
if (blockState.getLightValue() > 0)
{
this.blockLightPosList.add(new DhBlockPos(this.chunk.getPos().getXStart() + x, y, this.chunk.getPos().getZStart() + z));
}
}
}
}
#elif MC_VER < MC_1_20_1
this.chunk.getLights().forEach((blockPos) ->
{
this.blockLightPosList.add(new DhBlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ()));
@@ -652,11 +767,14 @@ public class ChunkWrapper implements IChunkWrapper
return this.blockLightPosList;
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public String toString() { return this.chunk.getClass().getSimpleName() + this.chunk.getPos(); }
@@ -672,4 +790,8 @@ public class ChunkWrapper implements IChunkWrapper
// return this.blockBiomeHashCode;
//}
//endregion
}
@@ -1,12 +1,19 @@
package com.seibel.distanthorizons.common.wrappers.gui;
#if MC_VER <= MC_1_12_2
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.util.text.ITextComponent;
#else
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
#endif
#if MC_VER < MC_1_20_1
#if MC_VER <= MC_1_12_2
#elif MC_VER < MC_1_20_1
import com.mojang.blaze3d.vertex.PoseStack;
#elif MC_VER <= MC_1_21_11
import net.minecraft.client.gui.GuiGraphics;
@@ -16,26 +23,73 @@ import net.minecraft.client.gui.GuiGraphicsExtractor;
import java.util.List;
#if MC_VER <= MC_1_12_2
public class DhScreen extends GuiScreen
#else
public class DhScreen extends Screen
#endif
{
#if MC_VER <= MC_1_12_2
protected ITextComponent title;
#endif
protected DhScreen(Component $$0)
#if MC_VER <= MC_1_12_2
protected DhScreen(ITextComponent title)
{
super($$0);
this.title = title;
}
#else
protected DhScreen(Component title)
{
super(title);
}
#endif
// addRenderableWidget in 1.17 and over
// addButton in 1.16 and below
#if MC_VER <= MC_1_12_2
protected GuiButton addBtn(GuiButton button)
#else
protected Button addBtn(Button button)
#endif
{
#if MC_VER < MC_1_17_1
#if MC_VER <= MC_1_12_2
this.buttonList.add(button);
return button;
#elif MC_VER < MC_1_17_1
return this.addButton(button);
#else
return this.addRenderableWidget(button);
#endif
}
#if MC_VER < MC_1_20_1
#if MC_VER <= MC_1_12_2
@Override
protected void actionPerformed(GuiButton button)
{
OnPressed handler = GuiHelper.HANDLER_BY_BUTTON.get(button);
if (handler != null)
{
handler.pressed(button);
}
}
protected void DhDrawCenteredString(ITextComponent text, int x, int y, int color) {
drawCenteredString(fontRenderer, text.getFormattedText(), x, y, color);
}
protected void DhDrawString(ITextComponent text, int x, int y, int color) {
drawString(fontRenderer, text.getFormattedText(), x, y, color);
}
protected void DhRenderComponentTooltip(List<ITextComponent> list, int x, int y) {
drawHoveringText(list.stream().map(ITextComponent::getFormattedText).toList(), x, y, fontRenderer);
}
protected void DhRenderTooltip(ITextComponent text, int x, int y) {
drawHoveringText(List.of(text.getFormattedText()), x, y, fontRenderer);
}
#elif MC_VER < MC_1_20_1
protected void DhDrawCenteredString(PoseStack guiStack, Font font, Component text, int x, int y, int color)
{
drawCenteredString(guiStack, font, text, x, y, color);
@@ -112,7 +166,4 @@ public class DhScreen extends Screen
guiStack.setTooltipForNextFrame(font, text, x, y);
}
#endif
}
@@ -0,0 +1,30 @@
package com.seibel.distanthorizons.common.wrappers.gui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import java.util.Objects;
public class DhScreenUtil
{
//================//
// helper methods //
//================//
//region
public static void setScreen(Screen screen)
{
#if MC_VER <= MC_1_12_2
Objects.requireNonNull(Minecraft.getMinecraft()).displayGuiScreen(screen);
#elif MC_VER <= MC_26_1_2
Objects.requireNonNull(Minecraft.getInstance()).setScreen(screen);
#else
Objects.requireNonNull(Minecraft.getInstance()).setScreenAndShow(screen);
#endif
}
//endregion
}
@@ -4,14 +4,22 @@ import com.seibel.distanthorizons.common.wrappers.gui.classicConfig.ClassicConfi
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.coreapi.ModInfo;
#if MC_VER <= MC_1_12_2
import net.minecraft.client.gui.GuiScreen;
#else
import net.minecraft.client.gui.screens.Screen;
#endif
import com.seibel.distanthorizons.core.logging.DhLogger;
public class GetConfigScreen
{
protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
#if MC_VER <= MC_1_12_2
public static GuiScreen getScreen(GuiScreen parent)
#else
public static Screen getScreen(Screen parent)
#endif
{
if (ModInfo.IS_DEV_BUILD)
{
@@ -1,11 +1,21 @@
package com.seibel.distanthorizons.common.wrappers.gui;
#if MC_VER <= MC_1_12_2
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation;
import java.util.HashMap;
import java.util.Map;
#else
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
#endif
#if MC_VER < MC_1_19_2
#if MC_VER < MC_1_19_2 && MC_VER > MC_1_12_2
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
#endif
@@ -15,57 +25,99 @@ public class GuiHelper
/**
* Helper static methods for versional compat
*/
#if MC_VER <= MC_1_12_2
public static final Map<GuiButton, OnPressed> HANDLER_BY_BUTTON = new HashMap<>();
#endif
#if MC_VER <= MC_1_12_2
public static GuiButton MakeBtn(ITextComponent base, int posX, int posZ, int width, int height, OnPressed action)
#else
public static Button MakeBtn(Component base, int posX, int posZ, int width, int height, Button.OnPress action)
#endif
{
#if MC_VER < MC_1_19_4
#if MC_VER <= MC_1_12_2
GuiButton button = new GuiButton(HANDLER_BY_BUTTON.size(), posX, posZ, width, height, base.getFormattedText());
HANDLER_BY_BUTTON.put(button, action);
return button;
#elif MC_VER < MC_1_19_4
return new Button(posX, posZ, width, height, base, action);
#else
return Button.builder(base, action).bounds(posX, posZ, width, height).build();
#endif
}
#if MC_VER <= MC_1_12_2
public static ITextComponent TextOrLiteral(String text)
#else
public static MutableComponent TextOrLiteral(String text)
#endif
{
#if MC_VER < MC_1_19_2
#if MC_VER <= MC_1_12_2
return new TextComponentString(text);
#elif MC_VER < MC_1_19_2
return new TextComponent(text);
#else
return Component.literal(text);
#endif
}
#if MC_VER <= MC_1_12_2
public static ITextComponent TextOrTranslatable(String text)
#else
public static MutableComponent TextOrTranslatable(String text)
#endif
{
#if MC_VER < MC_1_19_2
#if MC_VER <= MC_1_12_2
return new TextComponentString(text);
#elif MC_VER < MC_1_19_2
return new TextComponent(text);
#else
return Component.translatable(text);
#endif
}
#if MC_VER <= MC_1_12_2
public static ITextComponent Translatable(String text, Object... args)
#else
public static MutableComponent Translatable(String text, Object... args)
#endif
{
#if MC_VER < MC_1_19_2
#if MC_VER <= MC_1_12_2
return new TextComponentTranslation(text, args);
#elif MC_VER < MC_1_19_2
return new TranslatableComponent(text, args);
#else
return Component.translatable(text, args);
#endif
}
public static void SetX(AbstractWidget w, int x)
#if MC_VER <= MC_1_12_2
public static void SetX(GuiButton widget, int x)
#else
public static void SetX(AbstractWidget widget, int x)
#endif
{
#if MC_VER < MC_1_19_4
w.x = x;
widget.x = x;
#else
w.setX(x);
widget.setX(x);
#endif
}
public static void SetY(AbstractWidget w, int y)
#if MC_VER <= MC_1_12_2
public static void SetY(GuiTextField textField, int y) { textField.y = y; }
#endif
#if MC_VER <= MC_1_12_2
public static void SetY(GuiButton widget, int y)
#else
public static void SetY(AbstractWidget widget, int y)
#endif
{
#if MC_VER < MC_1_19_4
w.y = y;
widget.y = y;
#else
w.setY(y);
widget.setY(y);
#endif
}
@@ -1,21 +1,40 @@
package com.seibel.distanthorizons.common.wrappers.gui;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
#if MC_VER <= MC_1_12_2
import net.minecraft.client.resources.I18n;
#else
import net.minecraft.client.resources.language.I18n;
#endif
public class LangWrapper implements ILangWrapper
{
public static final LangWrapper INSTANCE = new LangWrapper();
@Override
public boolean langExists(String str)
{
#if MC_VER <= MC_1_12_2
return I18n.hasKey(str);
#elif MC_VER <= MC_26_1_2
return I18n.exists(str);
#else
String translated = getLang(str);
return translated != null
// if this isn't translatable it will generally return
// the same string as was passed in
&& !translated.equalsIgnoreCase(str);
#endif
}
@Override
public String getLang(String str)
{
#if MC_VER <= MC_1_12_2
return I18n.format(str);
#else
return I18n.get(str);
#endif
}
}
@@ -1,17 +1,27 @@
package com.seibel.distanthorizons.common.wrappers.gui;
#if MC_VER <= MC_1_12_2
import org.lwjglx.opengl.Display;
#else
import com.mojang.blaze3d.platform.Window;
#endif
import com.seibel.distanthorizons.core.config.gui.AbstractScreen;
import net.minecraft.client.Minecraft;
#if MC_VER > MC_1_12_2
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.screens.Screen;
#endif
import org.jetbrains.annotations.NotNull;
#if MC_VER < MC_1_20_1
#if MC_VER <= MC_1_12_2
import net.minecraft.client.gui.GuiListExtended;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiSlot;
#elif MC_VER < MC_1_20_1
import com.mojang.blaze3d.vertex.PoseStack;
#elif MC_VER <= MC_1_21_11
import net.minecraft.client.gui.GuiGraphics;
@@ -24,19 +34,36 @@ import java.util.*;
public class MinecraftScreen
{
#if MC_VER <= MC_1_12_2
public static GuiScreen getScreen(GuiScreen parent, AbstractScreen screen, String translationName)
#else
public static Screen getScreen(Screen parent, AbstractScreen screen, String translationName)
#endif
{
return new ConfigScreenRenderer(parent, screen, translationName);
}
//=========//
// screens //
//=========//
//region
private static class ConfigScreenRenderer extends DhScreen
{
#if MC_VER <= MC_1_12_2
private final GuiScreen parent;
#else
private final Screen parent;
#endif
private ConfigListWidget configListWidget;
private AbstractScreen screen;
#if MC_VER < MC_1_19_2
#if MC_VER <= MC_1_12_2
public static net.minecraft.util.text.TextComponentTranslation translate(String str, Object... args)
{ return new net.minecraft.util.text.TextComponentTranslation(str, args); }
#elif MC_VER < MC_1_19_2
public static net.minecraft.network.chat.TranslatableComponent translate(String str, Object... args)
{ return new net.minecraft.network.chat.TranslatableComponent(str, args); }
#else
@@ -44,10 +71,16 @@ public class MinecraftScreen
{ return net.minecraft.network.chat.Component.translatable(str, args); }
#endif
#if MC_VER <= MC_1_12_2
protected ConfigScreenRenderer(GuiScreen parent, AbstractScreen screen, String translationName)
#else
protected ConfigScreenRenderer(Screen parent, AbstractScreen screen, String translationName)
#endif
{
super(translate(translationName));
#if MC_VER < MC_1_21_9
#if MC_VER <= MC_1_12_2
screen.minecraftWindow = Display.getWindow();
#elif MC_VER < MC_1_21_9
screen.minecraftWindow = Minecraft.getInstance().getWindow().getWindow();
#else
screen.minecraftWindow = Minecraft.getInstance().getWindow().handle();
@@ -57,30 +90,53 @@ public class MinecraftScreen
}
@Override
#if MC_VER <= MC_1_12_2
public void initGui()
#else
protected void init()
#endif
{
super.init(); // Init Minecraft's screen
#if MC_VER <= MC_1_12_2
super.initGui();
#else
super.init();
#endif
#if MC_VER <= MC_1_12_2
this.screen.width = Display.getWidth();
this.screen.height = Display.getHeight();
#else
Window mcWindow = this.minecraft.getWindow();
this.screen.width = mcWindow.getWidth();
this.screen.height = mcWindow.getHeight();
#endif
this.screen.scaledWidth = this.width;
this.screen.scaledHeight = this.height;
this.screen.init(); // Init our own config screen
#if MC_VER <= MC_1_12_2
this.configListWidget = new ConfigListWidget(this.mc, this.width, this.height, 0, 0, 25); // Select the area to tint
#else
this.configListWidget = new ConfigListWidget(this.minecraft, this.width, this.height, 0, 0, 25); // Select the area to tint
#endif
#if MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
#if MC_VER <= MC_1_12_2
#elif MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
if (this.minecraft != null && this.minecraft.level != null) // Check if in game
{
this.configListWidget.setRenderBackground(false); // Disable from rendering
}
#endif
#if MC_VER > MC_1_12_2
this.addWidget(this.configListWidget); // Add the tint to the things to be rendered
#endif
}
@Override
#if MC_VER < MC_1_20_1
#if MC_VER <= MC_1_12_2
public void drawScreen(int mouseX, int mouseY, float delta)
#elif 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)
@@ -88,7 +144,9 @@ public class MinecraftScreen
public void extractRenderState(GuiGraphicsExtractor matrices, int mouseX, int mouseY, float delta)
#endif
{
#if MC_VER < MC_1_20_2
#if MC_VER <= MC_1_12_2
this.drawDefaultBackground();
#elif MC_VER < MC_1_20_2
this.renderBackground(matrices); // Render background
#elif MC_VER < MC_1_21_6
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
@@ -96,7 +154,9 @@ public class MinecraftScreen
// background blur is already being rendered, rendering again causes the game to crash
#endif
#if MC_VER <= MC_1_21_11
#if MC_VER <= MC_1_12_2
this.configListWidget.drawScreen(mouseX, mouseY, delta);
#elif MC_VER <= MC_1_21_11
this.configListWidget.render(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
#else
this.configListWidget.extractRenderState(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
@@ -106,55 +166,82 @@ public class MinecraftScreen
this.screen.mouseY = mouseY;
this.screen.render(delta); // Render everything on the main screen
#if MC_VER <= MC_1_21_11
#if MC_VER <= MC_1_12_2
super.drawScreen(mouseX, mouseY, delta); // Render the vanilla stuff (currently only used for the background and tint)
#elif MC_VER <= MC_1_21_11
super.render(matrices, mouseX, mouseY, delta); // Render the vanilla stuff (currently only used for the background and tint)
#else
super.extractRenderState(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
#endif
}
#if MC_VER <= MC_1_21_10
@Override
#if MC_VER <= MC_1_12_2
public void setWorldAndResolution(Minecraft mc, int width, int height)
#elif MC_VER <= MC_1_21_10
public void resize(Minecraft mc, int width, int height)
#else
@Override
public void resize(int width, int height)
#endif
{
// Resize Minecraft's screen
#if MC_VER <= MC_1_21_10
#if MC_VER <= MC_1_12_2
super.setWorldAndResolution(mc, width, height);
#elif MC_VER <= MC_1_21_10
super.resize(mc, width, height);
#else
super.resize(width, height);
#endif
#if MC_VER <= MC_1_12_2
this.screen.width = Display.getWidth();
this.screen.height = Display.getHeight();
#else
Window mcWindow = this.minecraft.getWindow();
this.screen.width = mcWindow.getWidth();
this.screen.height = mcWindow.getHeight();
#endif;
this.screen.scaledWidth = this.width;
this.screen.scaledHeight = this.height;
this.screen.onResize(); // Resize our screen
}
@Override
#if MC_VER <= MC_1_12_2
public void updateScreen()
#else
public void tick()
#endif
{
#if MC_VER <= MC_1_12_2
super.updateScreen(); // Tick Minecraft's screen
#else
super.tick(); // Tick Minecraft's screen
#endif
this.screen.tick(); // Tick our screen
if (this.screen.close) // If we decide to close the screen, then actually close the screen
{
#if MC_VER <= MC_1_12_2
this.onGuiClosed();
#else
this.onClose();
#endif
}
}
@Override
#if MC_VER <= MC_1_12_2
public void onGuiClosed()
#else
public void onClose()
#endif
{
this.screen.onClose(); // Close our screen
Objects.requireNonNull(this.minecraft).setScreen(this.parent); // Goto the parent screen
DhScreenUtil.setScreen(this.parent); // Goto the parent screen
}
#if MC_VER > MC_1_12_2
@Override
public void onFilesDrop(@NotNull List<Path> files)
{ this.screen.onFilesDrop(files); }
@@ -163,10 +250,14 @@ public class MinecraftScreen
@Override
public boolean shouldCloseOnEsc()
{ return this.screen.shouldCloseOnEsc; }
#endif
}
#if MC_VER <= MC_1_12_2
public static class ConfigListWidget extends GuiListExtended
#else
public static class ConfigListWidget extends ContainerObjectSelectionList
#endif
{
public ConfigListWidget(Minecraft minecraftClient, int canvasWidth, int canvasHeight, int topMargin, int botMargin, int itemSpacing)
{
@@ -178,6 +269,22 @@ public class MinecraftScreen
this.centerListVertically = false;
}
#if MC_VER <= MC_1_12_2
@Override
protected int getSize()
{
return 0;
}
@Override
public IGuiListEntry getListEntry(int index)
{
return null;
}
#endif
}
//endregion
}
@@ -0,0 +1,9 @@
package com.seibel.distanthorizons.common.wrappers.gui;
#if MC_VER <= MC_1_12_2
import net.minecraft.client.gui.GuiButton;
public interface OnPressed {
void pressed(GuiButton button);
}
#endif
@@ -19,13 +19,21 @@
package com.seibel.distanthorizons.common.wrappers.gui;
#if MC_VER > MC_1_12_2
import net.minecraft.network.chat.Component;
#endif
#if MC_VER >= MC_1_17_1
import net.minecraft.client.gui.components.Button;
#endif
#if MC_VER < MC_1_17_1
#if MC_VER <= MC_1_12_2
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.util.ResourceLocation;
#elif MC_VER < MC_1_17_1
import net.minecraft.client.gui.components.ImageButton;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
@@ -53,7 +61,9 @@ import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.renderer.RenderPipelines;
#endif
#if MC_VER <= MC_1_21_10
#if MC_VER <= MC_1_12_2
import net.minecraft.util.ResourceLocation;
#elif MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
@@ -65,7 +75,10 @@ import net.minecraft.resources.Identifier;
* @author coolGi
* @version 2023-10-03
*/
#if MC_VER < MC_1_20_2
#if MC_VER <= MC_1_12_2
@SuppressWarnings("deprecation") // we use a few deprecated Mojang functions (as expected when running on old MC versions)
public class TexturedButtonWidget extends GuiButton
#elif MC_VER < MC_1_20_2
@SuppressWarnings("deprecation") // we use a few deprecated Mojang functions (as expected when running on old MC versions)
public class TexturedButtonWidget extends ImageButton
#else
@@ -75,7 +88,7 @@ public class TexturedButtonWidget extends Button
{
public final boolean renderBackground;
#if MC_VER >= MC_1_20_2
#if MC_VER >= MC_1_20_2 || MC_VER <= MC_1_12_2
private final int u;
private final int v;
private final int hoveredVOffset;
@@ -90,30 +103,41 @@ public class TexturedButtonWidget extends Button
private final int textureHeight;
#endif
public TexturedButtonWidget(
int x, int y, int width, int height, int u, int v, int hoveredVOffset,
#if MC_VER <= MC_1_21_10 ResourceLocation textureResourceLocation,
#else Identifier textureResourceLocation,
#endif
int textureWidth, int textureHeight, OnPress pressAction, Component text)
#if MC_VER <= MC_1_12_2
public TexturedButtonWidget(int id, int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, int textureWidth, int textureHeight, String text)
{
this(id, x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, text, true);
}
#elif MC_VER <= MC_1_21_10
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text)
{
this(x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, pressAction, text, true);
}
public TexturedButtonWidget(
int x, int y, int width, int height, int u, int v, int hoveredVOffset,
#if MC_VER <= MC_1_21_10 ResourceLocation textureResourceLocation,
#else Identifier textureResourceLocation,
#endif
int textureWidth, int textureHeight, OnPress pressAction, Component text,
boolean renderBackground)
#else
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, Identifier textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text)
{
#if MC_VER < MC_1_20_2
this(x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, pressAction, text, true);
}
#endif
#if MC_VER <= MC_1_12_2
public TexturedButtonWidget(int id, int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, int textureWidth, int textureHeight, String text, boolean renderBackground)
#elif MC_VER <= MC_1_21_10
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text, boolean renderBackground)
#else
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, Identifier textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text, boolean renderBackground)
#endif
{
#if MC_VER <= MC_1_12_2
super(id, x, y, width, height, text);
#elif MC_VER < MC_1_20_2
super(x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, pressAction, text);
#else
// We don't pass in the text option since it will render (we normally pass it in for narration)
super(x, y, width, height, Component.empty(), pressAction, DEFAULT_NARRATION);
#endif
#if MC_VER >= MC_1_20_2 || MC_VER <= MC_1_12_2
this.u = u;
this.v = v;
this.hoveredVOffset = hoveredVOffset;
@@ -127,7 +151,27 @@ public class TexturedButtonWidget extends Button
this.renderBackground = renderBackground;
}
#if MC_VER < MC_1_20_2
#if MC_VER <= MC_1_12_2
@Override
public void drawButton(Minecraft mc, int mouseX, int mouseY, float partialTicks) {
if (this.visible) {
//Render vanilla background
mc.getTextureManager().bindTexture(BUTTON_TEXTURES);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
int i = this.getHoverState(this.hovered);
GlStateManager.enableBlend();
GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
this.drawTexturedModalRect(this.x, this.y, 0, 46 + i * 20, this.width / 2, this.height);
this.drawTexturedModalRect(this.x + this.width / 2, this.y, 200 - this.width / 2, 46 + i * 20, this.width / 2, this.height);
//Render DH texture
mc.getTextureManager().bindTexture(textureResourceLocation);
drawModalRectWithCustomSizedTexture(this.x, this.y, this.u, (hoveredVOffset * (i - 1)), this.width, this.height, this.textureWidth, this.textureHeight);
}
}
#elif MC_VER < MC_1_20_2
#if MC_VER < MC_1_19_4
@Override
public void renderButton(PoseStack matrices, int mouseX, int mouseY, float delta)

Some files were not shown because too many files have changed in this diff Show More