Compare commits

..

16 Commits

Author SHA1 Message Date
James Seibel b6b108a287 Merge branch 'stable' of gitlab.com:jeseibel/distant-horizons into stable 2024-09-04 07:08:38 -05:00
James Seibel 2a37bec8ff Merge tag '2.1.2a' into stable 2024-07-28 08:07:35 -05:00
James Seibel f0f864d824 update architectury.loom 1.1 -> 1.3 and gradle 7.6 -> 8.1
gradle update was required by architectury
2024-01-07 21:58:09 -06:00
James Seibel 5abbff42d8 update manifold 2023.1.29 -> 23.1.31 2024-01-07 21:57:13 -06:00
James Seibel 53e2c4f806 update 1.20.4 forge 49.0.3 -> 49.0.14 2024-01-07 21:56:54 -06:00
Rózsa Péter cb4c32e0a9 Fix clone URL
(cherry picked from commit 39b77c783b)
2023-12-25 18:37:02 +10:30
coolGi c620086ed1 Revert "Fixed 1.20.4 forge remap"
This reverts commit 0d565895e2.
2023-12-24 19:03:38 +10:30
coolGi 513cecf318 Revert "Hopefully fixed forge stable on 1.20.4"
This reverts commit 749921b436.
2023-12-24 19:03:31 +10:30
coolGi 749921b436 Hopefully fixed forge stable on 1.20.4 2023-12-23 15:39:20 +10:30
coolGi 0d565895e2 Fixed 1.20.4 forge remap
(cherry picked from commit 28d4cc86a9)
2023-12-23 15:35:12 +10:30
coolGi 2c6849a0fd Updated to new git url
(cherry picked from commit 0d7b0f9fe4)
2023-12-23 15:34:16 +10:30
James Seibel 4d53ec5b64 Fix forge 1.20.4 crashing due to incorrect version number order
(cherry picked from commit d597634ac6)
2023-12-23 15:33:59 +10:30
coolGi 4467af4798 Updated ci to include 1.20.4 2023-12-09 04:17:50 +00:00
coolGi d3f953686a Fixed up screens looking incorrect on 1.20.4 mc versions
(cherry picked from commit 04ddd83519)
2023-12-09 14:41:35 +10:30
coolGi 67901d82c5 Updated to 1.20.3/4
(cherry picked from commit 5b81ca2716)
2023-12-09 14:13:50 +10:30
James Seibel 013fbf638a Merge branch 'main' into 'stable'
merge 2.0.1a

See merge request jeseibel/distant-horizons!45
2023-12-04 01:11:27 +00:00
422 changed files with 8051 additions and 36880 deletions
+19
View File
@@ -0,0 +1,19 @@
**/.git
**/.gitlab
**/.cache
buildAllJars
**/_Misc Files
*.bat
*.md
*.sh
*.txt
coreSubProjects/*.md
coreSubProjects/*.txt
**/.gitignore
**/.gitattributes
**/.gitlab-cy.yml
**/.gitmodules
+2 -1
View File
@@ -5,13 +5,14 @@ root = true
[*] [*]
charset = utf-8 charset = utf-8
end_of_line = crlf
indent_size = 4 indent_size = 4
indent_style = space indent_style = space
insert_final_newline = false insert_final_newline = false
max_line_length = 1000 max_line_length = 1000
tab_width = 4 tab_width = 4
trim_trailing_whitespace = false trim_trailing_whitespace = false
ij_continuation_indent_size = 4 ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = true ij_formatter_tags_enabled = true
-6
View File
@@ -25,12 +25,6 @@ hs_err_pid*
Merged/ Merged/
# Folder created by the buildAll scripts # Folder created by the buildAll scripts
buildAllJars/ buildAllJars/
_buildAllJars/
_buildWorkers/
relocate_natives/.venv/
relocate_natives/__pycache__/
relocate_natives/apple-codesign/
# file from notepad++ # file from notepad++
*.bak *.bak
+29 -51
View File
@@ -1,10 +1,10 @@
# use Eclipse's JDK # use Eclipse's JDK
# The ci should always use a unix(-like) OS to work # The ci should always use a unix(-like) OS to work
image: eclipse-temurin:25 image: eclipse-temurin:21
# all stages need to be defined here # all stages need to be defined here
# TODO: Make stages depend on what is in versionProperties
stages: stages:
- translations
- build - build
- api - api
- pages - pages
@@ -18,54 +18,46 @@ variables:
.build_java: .build_java:
#image: eclipse-temurin:17 #image: eclipse-temurin:17
cache: cache:
key: "gradleCache_$CI_JOB_NAME_SLUG" key: "gradleCache"
policy: pull-push policy: pull-push
paths: paths:
- .gradle - .gradle
- cache/ - cache/
allow_failure: true allow_failure: true
retry:
max: 2
when:
- runner_system_failure
- stuck_or_timeout_failure
build: build:
stage: build stage: build
needs:
- job: translations
artifacts: true
parallel: parallel:
matrix: matrix:
- MC_VER: [ - MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6", "1.21.1"]
"26.1.2",
"1.21.11", "1.21.10", "1.21.9", "1.21.8", "1.21.6", "1.21.5", "1.21.4", "1.21.3", "1.21.1",
"1.20.6", "1.20.4", "1.20.2", "1.20.1",
"1.19.4", "1.19.2",
"1.18.2",
"1.17.1",
"1.16.5",
"1.12.2"
]
before_script:
# MC 1.12.2 needs both JDK 25 (for unimined) and JDK 8 (for MC 1.12)
# hopefully downloading the JDK 8 like this will solve that problem?
- apt-get update -q
- apt-get install -y openjdk-8-jdk
script: script:
# this both runs the unit tests and assembles the code # this both runs the unit tests and assembles the code
- ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/; - ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
- ./gradlew build -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/; - ./gradlew build -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
- cp ./fabric/build/libs/* ./forge/build/libs/* ./neoforge/build/libs/* ./build/forgix/* . || true - ./gradlew mergeJars -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
artifacts: artifacts:
name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}" name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths: paths:
- ./*.jar - Merged/*.jar
- quilt/build/libs/*.jar
- fabric/build/libs/*.jar
- forge/build/libs/*.jar
- neoforge/build/libs/*.jar
exclude: exclude:
- ./*-all.jar # TODO: There is a lot of duplicate stuff here, try to maybe make it smaller
- ./*-dev.jar - fabric/build/libs/*-all.jar
- ./*-sources.jar - fabric/build/libs/*-dev.jar
- fabric/build/libs/*-sources.jar
- quilt/build/libs/*-all.jar
- quilt/build/libs/*-dev.jar
- quilt/build/libs/*-sources.jar
- forge/build/libs/*-all.jar
- forge/build/libs/*-dev.jar
- forge/build/libs/*-sources.jar
- neoforge/build/libs/*-all.jar
- neoforge/build/libs/*-dev.jar
- neoforge/build/libs/*-sources.jar
expire_in: 14 days expire_in: 14 days
when: always when: always
extends: .build_java extends: .build_java
@@ -80,15 +72,15 @@ api:
# this also runs unit tests # this also runs unit tests
- ./gradlew api:build --gradle-user-home cache/; - ./gradlew api:build --gradle-user-home cache/;
- ./gradlew api:addSourcesToCompiledJar --gradle-user-home cache/; - ./gradlew api:addSourcesToCompiledJar --gradle-user-home cache/;
- cp ./coreSubProjects/api/build/libs/merged/* .
artifacts: artifacts:
name: "NightlyBuild_Api-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}" name: "Api_NightlyBuild-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths: paths:
- ./*.jar - coreSubProjects/api/build/libs/merged/*.jar
# can be uncommented if we don't want a jar with the source code
# - coreSubProjects/api/build/libs/*.jar
exclude: exclude:
- ./*-all.jar - coreSubProjects/api/build/libs/merged/*-all.jar
- ./*-dev.jar - coreSubProjects/api/build/libs/merged/*-sources.jar
- ./*-sources.jar
expire_in: 1 day expire_in: 1 day
when: always when: always
extends: .build_java extends: .build_java
@@ -111,17 +103,3 @@ pages:
- public - public
allow_failure: false allow_failure: false
extends: .build_java 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
+3 -3
View File
@@ -6,13 +6,13 @@ Or click the checkbox once the issue has been created.
--> -->
1. [ ] Check the FAQ to see if your issue has already been reported and has a solution: 1. [ ] Check the FAQ to see if your issue has already been reported and has a solution:
[Problems-and-solutions](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/2-problems-and-solutions/Problems-and-Solutions) [Problems-and-solutions](https://gitlab.com/jeseibel/distant-horizons/-/wikis/2-frequently-asked-questions/2-problems-and-solutions/Problems-and-Solutions)
2. [ ] Make sure you are not using any mods on the incompatible list: 2. [ ] Make sure you are not using any mods on the incompatible list:
[Mod support FAQ](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/4-mod-support/Mod-Support) [Mod support FAQ](https://gitlab.com/jeseibel/distant-horizons/-/wikis/2-frequently-asked-questions/4-mod-support/Mod-Support)
3. [ ] Check the existing issues to verify that your bug hasn't already been submitted: 3. [ ] Check the existing issues to verify that your bug hasn't already been submitted:
[Issues](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues) [Issues](https://gitlab.com/jeseibel/distant-horizons/-/issues/)
4. [ ] Upload Minecraft's crash report and/or log. \ 4. [ ] Upload Minecraft's crash report and/or log. \
Minecraft crash reports are located in: `.minecraft/crash-reports` \ Minecraft crash reports are located in: `.minecraft/crash-reports` \
+2 -36
View File
@@ -1,37 +1,3 @@
## Check off each item in this list before submitting: Before creating an issue, please select the appropriate template from the dropdown above.
<!--
To mark a section as complete either put an "x" in between the square brackets, example: "[x]"
Or click the checkbox once the issue has been created.
-->
1. [ ] Check the FAQ to see if your issue has already been reported and has a solution:
[Problems-and-solutions](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/2-problems-and-solutions/Problems-and-Solutions)
2. [ ] Make sure you are not using any mods on the incompatible list:
[Mod support FAQ](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/4-mod-support/Mod-Support)
3. [ ] Check the existing issues to verify that your bug hasn't already been submitted:
[Issues](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues)
4. [ ] Upload Minecraft's crash report and/or log. \
Minecraft crash reports are located in: `.minecraft/crash-reports` \
Minecraft logs are located in: `.minecraft/logs`
5. [ ] Upload your Distant Horizons Config. \
The config is found in: `.minecraft/configs/DistantHorizons.toml`
6. [ ] Fill out the information below:
* **minecraft version**:
* **Distant Horizons version**:
* **Mod loader**:
* **Installed mods (list the smallest number of mods that you can use to re-create the bug)**:
* **Describe the bug**:
* **Steps to reproduce the bug**:
The template will walk you through submitting a bug, feature, or improvement request.
+1 -1
View File
@@ -1,4 +1,4 @@
- [ ] Check the existing [feature requests](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues?sort=updated_desc&state=opened&label_name%5B%5D=Feature) to verify that your feature hasn't already been suggested. - [ ] Check the existing [feature requests](https://gitlab.com/jeseibel/distant-horizons/-/issues/?sort=updated_desc&state=opened&label_name%5B%5D=Feature) to verify that your feature hasn't already been suggested.
1. **Describe the feature**: 1. **Describe the feature**:
@@ -1,3 +1,3 @@
1. Check the existing [improvement requests](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues?sort=updated_desc&state=all&label_name%5B%5D=Improvement) to verify that your improvement hasn't already been suggested. 1. Check the existing [improvement requests](https://gitlab.com/jeseibel/distant-horizons/-/issues/?sort=updated_desc&state=all&label_name%5B%5D=Improvement) to verify that your improvement hasn't already been suggested.
2. **Describe the improvement**: 2. **Describe the improvement**:
-16
View File
@@ -1,16 +0,0 @@
# See mailmap docs: https://git-scm.com/docs/gitmailmap
# Test with git shortlog --summary --email
# Keep sorted for easier editing and smaller diffs
Ada Aster <an.ada.poirier@gmail.com>
CodeF53 <fseusb@gmail.com> <37855219+CodeF53@users.noreply.github.com>
coolGi <me@coolgi.dev> <sasanaps@hotmail.com>
James Seibel <jeseibel@gondtc.com> <jseibel@vertsys.com>
Morippi <leoleo97@libero.it> <leoloe97@libero.it>
Morippi <leoleo97@libero.it> <Morippi>
Ran <43445785+Ran-Mewo@users.noreply.github.com> <10044908-_Ran@users.noreply.gitlab.com>
Ran <43445785+Ran-Mewo@users.noreply.github.com> <43445785+Ran-Mewo@users.noreply.github.com>
Ran <43445785+Ran-Mewo@users.noreply.github.com> <43445785+RanCraftPlayz@users.noreply.github.com>
TomTheFurry <tomlee92502@yahoo.com>
TomTheFurry <tomlee92502@yahoo.com> <46843632+TomTheFurry@users.noreply.github.com>
Yeshi <yeshi@newengine.org>
-7
View File
@@ -1,7 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Fabric Client &amp; Server" type="CompoundRunConfigurationType">
<toRun name="distant-horizons [fabric:runClient]" type="GradleRunConfiguration" />
<toRun name="distant-horizons [fabric:runServer]" type="GradleRunConfiguration" />
<method v="2" />
</configuration>
</component>
-7
View File
@@ -1,7 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Forge Client &amp; Server" type="CompoundRunConfigurationType">
<toRun name="Forge Client (gradle)" type="GradleRunConfiguration" />
<toRun name="Forge Server (gradle)" type="GradleRunConfiguration" />
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Forge Client (gradle)" 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="forge:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Forge Server (gradle)" 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="forge:runServer" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-7
View File
@@ -1,7 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Neoforge Client &amp; Server" type="CompoundRunConfigurationType">
<toRun name="Neoforge Client (gradle)" type="GradleRunConfiguration" />
<toRun name="Neoforge Server (gradle)" type="GradleRunConfiguration" />
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Neoforge Client (gradle)" 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="neoforge:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Neoforge Server (gradle)" 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="neoforge:runServer" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [build]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<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="build" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [clean]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<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="clean" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,27 +0,0 @@
<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>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [core:build]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<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="core:build" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [fabric:runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<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="fabric:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [forge:runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<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="forge:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [mergeJars]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<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="mergeJars" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [neoforge:runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<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="neoforge:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [test]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<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="test" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
+12
View File
@@ -0,0 +1,12 @@
FROM eclipse-temurin:17-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] =========="
-1
View File
@@ -1 +0,0 @@
Distant Horizons logos © 2024 by Pankakes are licensed under CC BY-SA 4.0
+130 -37
View File
@@ -1,4 +1,4 @@
# <img src="https://gitlab.com/distant-horizons-team/distant-horizons-core/-/raw/main/_Misc%20Files/logo%20files/new/SVG/Distant-Horizons.svg" height="128px"> # <img src="https://gitlab.com/jeseibel/distant-horizons-core/-/raw/main/_Misc%20Files/logo%20files/LOD%20logo%20flat%20-%20with%20boarder.png" width="32"> Distant Horizons
_See farther without turning your game into a slide show._ _See farther without turning your game into a slide show._
<br> <br>
@@ -12,18 +12,91 @@ 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> <a href="https://youtu.be/SxQdbtjGEsc" target="_blank">![Distant Horizons - Alpha 2.0](https://i.ytimg.com/vi/SxQdbtjGEsc/hqdefault.jpg)</a>
## Translations <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
[![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> <br>
## Source Code Installation ## Source Code Installation
### Prerequisites ### Prerequisites
* A Java Development Kit (JDK) for Java 25 (recommended) or newer. <br> * A Java Development Kit (JDK) for Java 17 (recommended) or newer. <br>
Visit https://www.oracle.com/java/technologies/downloads/ for installers. Visit https://www.oracle.com/java/technologies/downloads/ for installers.
* Git or someway to clone git projects. <br> * Git or someway to clone git projects. <br>
Visit https://git-scm.com/ for installers. Visit https://git-scm.com/ for installers.
@@ -31,10 +104,15 @@ Guidelines: [translations.md](translations.md)
**If using IntelliJ:** **If using IntelliJ:**
1. Install the Manifold plugin 1. Install the Manifold plugin
- https://plugins.jetbrains.com/plugin/10057-manifold-ij
2. Open IDEA and import the build.gradle 2. Open IDEA and import the build.gradle
3. Refresh the Gradle project in IDEA if required 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> <br>
## Switching Versions ## Switching Versions
@@ -49,42 +127,72 @@ In IntelliJ, you will also need to do a gradle sync if it didn't happen automati
## Compiling ## Compiling
Prerequisites: Prerequisites:
- JDK 25 or newer - JDK 17 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`
5. The compiled jar file will be in the folder `\build\libs`
From the File Explorer: From the File Explorer:
1. Download and extract the project zip 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` 2. Download the core from https://gitlab.com/jeseibel/distant-horizons-core and extract into a folder called `coreSubProjects`
3. Open command prompt/terminal in the project folder 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` 4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows)
6. The compiled jar file will be in the folder `\build\libs` 5. Merge the jars with `./gradlew mergeJars`
6. The compiled jar file will be in the folder `Merged`
From the command line:
1. `git clone --recurse-submodules https://gitlab.com/jeseibel/distant-horizons.git`
2. `cd distant-horizons`
3. `./gradlew assemble`
4. `./gradlew mergeJars`
5. The compiled jar file will be in the folder `Merged`
Run tests with: `./gradlew test`
>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.\ >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` > For example: `./gradlew assemble -PmcVer=1.18.2`
<br> <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 ## 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> Run the standalone jar: `./gradlew run` <br>
Build the standalone jar: `./gradlew core:build` <br> Build the standalone jar: `./gradlew core:build` <br>
Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build` <br> Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build` <br>
Only build Forge: `./gradlew forge:assemble` or `./gradlew forge: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 Fabric client (for debugging): `./gradlew fabric:runClient` <br>
Run the Forge client (for debugging): `./gradlew forge: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` To build all versions: `./buildAll` (all builds will end up in the `Merged` folder)
<br> <br>
## Open Source Libraries ## Open Source Acknowledgements
Forgix (To merge multiple mod versions into one jar) [_Formerly_ [_DHJarMerger_](https://github.com/Ran-helo/DHJarMerger)]\ Forgix (To merge multiple mod versions into one jar) [_Formerly_ [_DHJarMerger_](https://github.com/Ran-helo/DHJarMerger)]\
https://github.com/PacifistMC/Forgix https://github.com/PacifistMC/Forgix
@@ -100,18 +208,3 @@ https://github.com/blackears/svgSalamander
sqlite-jdbc\ sqlite-jdbc\
https://github.com/xerial/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>.
+632 -24
View File
@@ -1,34 +1,642 @@
plugins { plugins {
id 'root' id "java"
id 'io.github.pacifistmc.forgix' version '2.+'
// Plugin to put dependencies inside our final jar
id "com.github.johnrengelman.shadow" version '8.1.1' apply false
// Plugin to create merged jars
id "io.github.pacifistmc.forgix" version "1.2.9"
// Manifold preprocessor
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
// Architectury is used here only as a replacement for forge's own loom
id "dev.architectury.loom" version "1.6-SNAPSHOT" apply false
} }
/**
* Creates the list of preprocessors to use.
*
* @param mcVers array of all MC versions
* @param mcIndex array index of the currently active MC version
*/
def writeBuildGradlePredefine(List<String> mcVers, int mcIndex)
{
// Build the list of preprocessors to use
StringBuilder sb = new StringBuilder();
sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n");
for (int i = 0; i < mcVers.size(); i++)
{
String verStr = mcVers[i].replace(".", "_");
sb.append("MC_" + verStr + "=" + i.toString() + "\n");
if (mcIndex == i)
sb.append("MC_VER=" + i.toString() + "\n");
}
// Check if this is a development build
if (mod_version.toLowerCase().contains("dev"))
{
// WARNING: only use this for logging, we don't want to have confusion
// when a method doesn't work correctly in the release build.
sb.append("DEV_BUILD=\n");
}
new File(projectDir, "build.properties").text = sb.toString()
}
// Transfers the values set in settings.gradle to the rest of the project
project.gradle.ext.getProperties().each { prop ->
rootProject.ext.set(prop.key, prop.value)
//println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
}
// Sets up manifold stuff
writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
// Sets up the version string (the name we use for our jar)
rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm")
// Forgix settings (used for merging jars)
forgix { forgix {
group = "com.seibel.distanthorizons"
mergedJarName = "DistantHorizons-${rootProject.versionStr}.jar"
// add the mod loaders to the end of the jar if (findProject(":forge"))
// put together in the format: "a", "a-b", "a-b-c" forge {
int loaderCount = 0; jarLocation = "build/libs/DistantHorizons-forge-${rootProject.versionStr}.jar"
String modLoaders = "";
((String) gradle.builds_for)
.split(",")
.each
{ loader ->
def loaderName = loader.trim()
if (modLoaders != "")
{
modLoaders += "-";
}
modLoaders += loaderName;
loaderCount++;
} }
// run if there are multiple launchers that need merging if (findProject(":neoforge"))
autoRun = (loaderCount > 1); custom {
projectName = "neoforge"
jarLocation = "build/libs/DistantHorizons-neoforge-${rootProject.versionStr}.jar"
}
// merged jars are named in the format: if (findProject(":fabric"))
// "DistantHorizons-3.0.1-b-dev-26.1-fabric-neoforge.jar" fabric {
archiveClassifier = modLoaders jarLocation = "build/libs/DistantHorizons-fabric-${rootProject.versionStr}.jar"
}
if (findProject(":quilt"))
quilt {
jarLocation = "build/libs/DistantHorizons-quilt-${rootProject.versionStr}.jar"
}
removeDuplicate "com.seibel.distanthorizons"
} }
subprojects { p ->
// Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")"
// Useful later on so we dont have duplicated code
def isMinecraftSubProject = p != project(":core") && p != project(":api")
// Apply plugins
apply plugin: "java"
apply plugin: "com.github.johnrengelman.shadow"
if (isMinecraftSubProject)
apply plugin: "systems.manifold.manifold-gradle-plugin"
// Apply forge's loom
if ((findProject(":forge") && p == project(":forge")) ||
(findProject(":neoforge") && p == project(":neoforge"))
)
{
apply plugin: "dev.architectury.loom"
}
// Set the manifold version (may not be required tough)
manifold {
manifoldVersion = rootProject.manifold_version
}
// set up custom configurations (configurations are a way to handle dependencies)
configurations {
// extends the shadowJar configuration
shadowMe
// have implemented dependencies automatically embedded in the final jar
implementation.extendsFrom(shadowMe)
// Configuration fpr core & api
coreProjects
shadowMe.extendsFrom(coreProjects)
// FIXME this additional configuration is necessary because forge
// needs forgeRuntimeLibrary, although adding it to shadowMe
// causes runtime issues where the libraries aren't properly added
forgeShadowMe
// this should match shadowMe pretty closely
implementation.extendsFrom(forgeShadowMe)
shadowMe.extendsFrom(forgeShadowMe)
forgeRuntimeLibrary.extendsFrom(forgeShadowMe)
if (isMinecraftSubProject && p != project(":common")) {
// Shadow common
common
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
if (findProject(":forge"))
developmentForge.extendsFrom common
if (findProject(":neoforge"))
developmentNeoForge.extendsFrom common
compileClasspath.extendsFrom coreProjects
runtimeClasspath.extendsFrom coreProjects
if (findProject(":forge"))
developmentForge.extendsFrom coreProjects
if (findProject(":neoforge"))
developmentNeoForge.extendsFrom coreProjects
if (findProject(":fabricLike") && p != project(":fabricLike")) {
// Shadow fabricLike
fabricLike
shadowFabricLike
compileClasspath.extendsFrom fabricLike
runtimeClasspath.extendsFrom fabricLike
}
}
}
dependencies {
//=====================//
// shared dependencies //
//=====================//
// Manifold
if (isMinecraftSubProject) {
annotationProcessor("systems.manifold:manifold-preprocessor:${rootProject.manifold_version}")
}
// Log4j
// TODO: Change to shadowMe later to work in the standalone jar
// We cannot do this now as it would break Quilt
implementation("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}")
implementation("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
// JOML
if (project.hasProperty("embed_joml") && embed_joml == "true")
forgeShadowMe("org.joml:joml:${rootProject.joml_version}")
else
implementation("org.joml:joml:${rootProject.joml_version}")
// JUnit tests
implementation("org.junit.jupiter:junit-jupiter:5.8.2")
implementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
implementation("junit:junit:4.13")
// FastUtil
// Note: MC 1.16 uses 8.2.1, and versions after use 8.5.12
// We cannot relocate this library since we call some MC classes that reference it
implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}")
// Compression
forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4
forgeShadowMe("org.tukaani:xz:${rootProject.xz_version}") // LZMA
// Sqlite Database
forgeShadowMe("org.xerial:sqlite-jdbc:${rootProject.sqlite_jdbc_version}")
// NightConfig (includes Toml & Json)
forgeShadowMe("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
forgeShadowMe("com.electronwill.night-config:json:${rootProject.nightconfig_version}")
// SVG (not needed atm)
// forgeShadowMe("com.formdev:svgSalamander:${rootProject.svgSalamander_version}")
// Netty
// Breaks 1.16.5
//forgeShadowMe("io.netty:netty-all:${rootProject.netty_version}")
// Remember, for lwjgl dependencies that arent included in Minecraft, you need to also need to add it to the ShadowJar thing
forgeShadowMe("org.lwjgl:lwjgl-jawt:${rootProject.lwjgl_version}") {
exclude group: "org.lwjgl", module: "lwjgl" // This module is imported by Minecraft so exclude it
}
//==========================//
// conditional dependencies //
//==========================//
// Add core
if (isMinecraftSubProject) {
coreProjects(project(":core")) {
// Remove Junit test libraries
exclude group: "org.junit.jupiter", module: "junit-jupiter"
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
exclude group: "junit", module: "junit"
// Removed dependencies
transitive false
}
}
// Add the api
if (p != project(":api")) {
coreProjects(project(":api")) {
// Remove Junit test libraries
exclude group: "org.junit.jupiter", module: "junit-jupiter"
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
exclude group: "junit", module: "junit"
// Removed dependencies
transitive false
}
}
// Add common
if (isMinecraftSubProject && p != project(":common")) {
// Common
common(project(":common")) { transitive false }
shadowCommon(project(":common")) { transitive false }
// FabricLike
if (findProject(":fabricLike") && p != project(":fabricLike")) {
fabricLike(project(path: ":fabricLike")) { transitive false }
shadowFabricLike(project(path: ":fabricLike")) { transitive false }
}
}
}
shadowJar {
configurations = [project.configurations.shadowMe]
if (isMinecraftSubProject && p != project(":common")) {
configurations.push(project.configurations.shadowCommon) // Shadow the common subproject
relocate "com.seibel.distanthorizons.common", "loaderCommon.${p.name}.com.seibel.distanthorizons.common" // Move the loader files to a different location
if (findProject(":fabricLike") && p != project(":fabricLike")) {
configurations.push(project.configurations.shadowFabricLike) // Shadow the fabricLike subproject
relocate "com.seibel.distanthorizons.fabriclike", "loaderCommon.${p.name}.com.seibel.distanthorizons.fabriclike" // Move the loader files to a different location
}
}
def librariesLocation = "DistantHorizons.libraries"
// LWJGL
// Only ever shadow the dependencies we use otherwise some stuff would break when running on an external client
relocate "org.lwjgl.system.jawt", "${librariesLocation}.lwjgl.system.jawt"
// Compression (LZ4)
relocate "net.jpountz", "${librariesLocation}.jpountz"
// Sqlite Database
//At the moment, there is a bug in this library which doesnt allow it to be relocated
// relocate "org.sqlite", "${librariesLocation}.sqlite"
// JOML
if (project.hasProperty("embed_joml") && embed_joml == "true")
relocate "org.joml", "${librariesLocation}.joml"
// NightConfig (includes Toml & Json)
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
// SVG (not needed atm)
// relocate "com.kitfox.svg", "${librariesLocation}.kitfox.svg"
// Netty
relocate "io.netty", "${librariesLocation}.netty"
mergeServiceFiles()
}
// Using jar.finalizedBy(shadowJar) causes issues so we do this scuffed bypass
jar.dependsOn(shadowJar)
// Put stuff from gradle.properties into the mod info
processResources {
def resourceTargets = [ // Location of where to inject the properties
// Holds info like git commit
// TODO: For some reason this script doesnt work with the core project
"build_info.json",
// Properties for each of the loaders
"fabric.mod.json",
"quilt.mod.json",
"META-INF/mods.toml",
"META-INF/neoforge.mods.toml",
// The mixins for each of the loaders
"DistantHorizons."+ p.name +".fabricLike.mixins.json"
]
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
// Fix forge version numbering system as it is weird
// For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"]
def compatible_forgemc_versions = "${compatible_minecraft_versions}".replaceAll("\"", "").replaceAll("]", ",)")
// println compatible_forgemc_versions
// Quilt's custom contributors system
// This has to be like
// "Person": "Developer", "Another person": "Developer"
def quilt_contributors = []
def mod_author_list = mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",")
for (dev in mod_author_list) {
quilt_contributors.push("\"${dev.strip()}\": \"Developer\"")
}
quilt_contributors.reverse()
//println quilt_contributors.join(", ")
// TODO: Find something we can use so we can basically re-map only when the jar is shadowed and relocated
// println p.tasks.findByName('shadowJar')
// These "hasProperty"'s are so that they can be passed through the cli (ie in the CI)
try {
if (infoGitCommit == "null")
infoGitCommit = 'git rev-parse --verify HEAD'.execute().text.trim()
if (infoGitBranch == "null")
infoGitBranch = 'git symbolic-ref --short HEAD'.execute().text.trim()
} catch (Exception e) {
infoGitCommit = infoGitBranch = "Git not found"
println "Git or Git project not found"
}
// The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties
def replaceProperties = [
version : mod_version,
mod_name : mod_readable_name,
group : maven_group,
authors : mod_authors,
description : mod_description,
homepage : mod_homepage,
source : mod_source,
issues : mod_issues,
discord : mod_discord,
minecraft_version : minecraft_version,
compatible_minecraft_versions: compatible_minecraft_versions,
compatible_forgemc_versions : compatible_forgemc_versions,
java_version : java_version,
quilt_contributors : "{"+quilt_contributors.join(", ")+"}",
info_git_commit : infoGitBranch,
info_git_branch : infoGitCommit,
info_build_source : infoBuildSource,
fabric_incompatibility_list : fabric_incompatibility_list,
fabric_recommend_list : fabric_recommend_list,
]
// replace any properties in the sub-projects with the values defined here
inputs.properties replaceProperties
replaceProperties.put "project", project
filesMatching(resourceTargets) {
expand replaceProperties
}
intoTargets.each { target ->
if (file(target).exists()) {
copy {
from(sourceSets.main.resources) {
include resourceTargets
expand replaceProperties
}
into target
}
}
}
// ==================== Delete un-needed files ====================
exclude "DistantHorizons.fabricLike.mixins.json" // This isnt required atm, but we will be using it later
// exclude "*.distanthorizons.accesswidener"
//// include "${accessWidenerVersion}.distanthorizons.accesswidener"
// Jank solution to remove all unused accesswideners
// The line above would work..., except that (neo)forge (well, mainly architectury) requires the original accesswidener file, meaning we require this jank solution to keep it
exclude { file ->
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${accessWidenerVersion}.distanthorizons.accesswidener") {
return true
}
return false
}
}
// Adds the standalone jar's entrypoint
jar {
from "LICENSE.txt"
manifest {
attributes(
'Implementation-Title': rootProject.mod_name,
'Implementation-Version': rootProject.mod_version,
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain' // When changing the main of the jar change this line
)
}
}
// this can be un-commented if we ever wanted to make DH modular (AKA use a module-info.java file) again
/*
// Tells gradle where to look for other modules
// Why isn't the classpath added to the modules path by default?
if (p == project(":core")) {
compileJava {
inputs.property('moduleName', 'dhApi')
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath
]
classpath = files()
}
}
}
*/
}
allprojects { p ->
// Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")"
// Useful later on so we dont have duplicated code
def isMinecraftSubProject = p != project(":core") && p != project(":api")
apply plugin: "java"
apply plugin: "maven-publish"
archivesBaseName = rootProject.mod_name
version = project.name + "-" + rootProject.versionStr
group = rootProject.maven_group
// this is the text that appears at the top of the overview (home) page
// and is used when bookmarking a page
javadoc.title = rootProject.mod_name + "-" + project.name
// Some annotations arent "technically" part of the official java standard,
// so we define it ourself here
javadoc {
configure( options ) {
tags(
'todo:X"',
'apiNote:a:API Note:',
'implSpec:a:Implementation Requirements:',
'implNote:a:Implementation Note:'
)
}
}
repositories {
// The central repo
mavenCentral()
// Used for Google's Collect library
maven { url "https://repo.enonic.com/public/" }
// For parchment mappings
maven { url "https://maven.parchmentmc.org" }
// For Architectury API
maven { url "https://maven.architectury.dev" }
// For Git repositories
maven { url "https://jitpack.io" }
// For Manifold Preprocessor
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
// Required for importing Modrinth mods
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
content {
includeGroup "maven.modrinth"
}
}
// Required for importing CursedForge mods
maven {
url "https://www.cursemaven.com"
content {
includeGroup "curse.maven"
}
}
// VanillaGradle and Mixins in common
maven { url "https://repo.spongepowered.org/maven/" }
// Canvas mod
maven { url "https://maven.vram.io/" }
// ModMenu mod
maven { url "https://maven.terraformersmc.com/" }
// neoforge
maven { url "https://maven.neoforged.net/releases/" }
// These 3 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
flatDir {
dirs "${rootDir}/mods/fabric"
content {
includeGroup "fabric-mod"
}
}
flatDir {
dirs "${rootDir}/mods/quilt"
content {
includeGroup "quilt-mod"
}
}
flatDir {
dirs "${rootDir}/mods/forge"
content {
includeGroup "forge-mod"
}
}
// TODO: If neoforged is ever needed, should we use that, or call it a forge mod?
}
// Adds some dependencies that are in vanilla but not in core
if (p == project(":core")) {
OperatingSystem os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem;
// Set the OS lwjgl is using to the current os
project.ext.lwjglNatives = "natives-" + os.toFamilyName()
dependencies { // All of these dependencies are in Vanilla Minecraft, but we need to depend on it as we arent importing Minecraft in the core
// Imports most of lwjgl's libraries (well, only the ones that we need)
implementation platform("org.lwjgl:lwjgl-bom:${rootProject.lwjgl_version}") // TODO: Use Minecraft's version for lwjgl_version (which changes in nearly every version) instead of a hard defined version for all versions
// REMEMBER: Dont shadow stuff here, these are just the libs that are included in Minecraft so that the core can use
implementation "org.lwjgl:lwjgl"
implementation "org.lwjgl:lwjgl-assimp"
implementation "org.lwjgl:lwjgl-glfw"
implementation "org.lwjgl:lwjgl-openal"
implementation "org.lwjgl:lwjgl-opengl"
implementation "org.lwjgl:lwjgl-stb"
implementation "org.lwjgl:lwjgl-tinyfd"
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-assimp::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-tinyfd::$lwjglNatives"
implementation "org.joml:joml:${rootProject.joml_version}"
// Some other dependencies
implementation("org.jetbrains:annotations:16.0.2")
implementation("com.google.code.findbugs:jsr305:3.0.2")
implementation("com.google.common:google-collect:0.5")
implementation("com.google.guava:guava:31.1-jre")
}
}
task copyCommonLoaderResources(type: Copy) {
from project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
into(file(p.file("build/resources/main")))
rename "${accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
// Move the fabricLike mixin to its different places for each subproject
if (findProject(":fabricLike")) {
from project(":fabricLike").file("src/main/resources/DistantHorizons.fabricLike.mixins.json")
into(file(p.file("build/resources/main")))
rename "DistantHorizons.fabricLike.mixins.json", "DistantHorizons." + p.name + ".fabricLike.mixins.json"
}
}
task copyCoreResources(type: Copy) {
from fileTree(project(":core").file("src/main/resources"))
into p.file("build/resources/main")
}
tasks.withType(JavaCompile) {
if (isMinecraftSubProject) {
options.release = rootProject.java_version as Integer
options.compilerArgs += ["-Xplugin:Manifold"]
} else {
options.release = 8; // Core & Api should use Java 8 no matter what
//options.release = rootProject.java_version as Integer // But if you want to test some stuff, then this can be enabled
}
options.encoding = "UTF-8"
}
java {
withSourcesJar()
}
}
// Delete the merged folder when running clean
task cleanMergedJars() {
def mergedFolder = file("Merged")
if (mergedFolder.exists()) {
delete(mergedFolder)
}
}
// add cleanMergedJars to the end of the "clean" task
tasks["clean"].finalizedBy(cleanMergedJars)
+7 -10
View File
@@ -1,9 +1,7 @@
#!/bin/sh #!/bin/sh
echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ====================" echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ===================="
mkdir -p buildAllJars mkdir -p buildAllJars | true
rm -rf buildAllJars/*
rm -rf build/forgix/*
# Loop trough everything in the version properties folder # Loop trough everything in the version properties folder
for d in versionProperties/*; do for d in versionProperties/*; do
@@ -13,13 +11,12 @@ for d in versionProperties/*; do
# Clean out the folders, build it, and merge it # Clean out the folders, build it, and merge it
# (We could use "./" to run gradlew, but as it is a shell script im going to be running it with the "sh" command) # (We could use "./" to run gradlew, but as it is a shell script im going to be running it with the "sh" command)
echo "==================== Cleaning workspace to build $version ====================" echo "==================== Cleaning workspace to build $version ===================="
sh gradlew clean -PmcVer=$version sh gradlew clean -PmcVer=$version --no-daemon || true
if [ $? != 0 ]; then continue; fi
echo "====================Building $version ====================" echo "====================Building $version ===================="
sh gradlew build -PmcVer=$version sh gradlew build -PmcVer=$version --no-daemon || true
if [ $? != 0 ]; then continue; fi echo "==================== Merging $version ===================="
sh gradlew mergeJars -PmcVer=$version --no-daemon || true
echo "==================== Moving jar ====================" echo "==================== Moving jar ===================="
mv build/forgix/*.jar buildAllJars/ mv Merged/*.jar buildAllJars/ || true
# The "| true" at the end of those are just to make sure the script continues even if a build fails
done done
+6 -8
View File
@@ -5,8 +5,6 @@
echo ==================== Note: All build jars will be in the folder called 'buildAllJars' ==================== echo ==================== Note: All build jars will be in the folder called 'buildAllJars' ====================
mkdir buildAllJars mkdir buildAllJars
del buildAllJars/*
del build/forgix/*
@rem Loop trough everything in the version properties folder @rem Loop trough everything in the version properties folder
for %%f in (versionProperties\*) do ( for %%f in (versionProperties\*) do (
@@ -15,13 +13,13 @@ for %%f in (versionProperties\*) do (
@rem Clean out the folders, build it, and merge it @rem Clean out the folders, build it, and merge it
echo ==================== Cleaning workspace to build !version! ==================== echo ==================== Cleaning workspace to build !version! ====================
call .\gradlew.bat clean call .\gradlew.bat clean -PmcVer="!version!" --no-daemon
echo ==================== Building !version! ====================
echo ==================== Building !version! ==================== call .\gradlew.bat build -PmcVer="!version!" --no-daemon
call .\gradlew.bat build -PmcVer="!version!" echo ==================== Merging !version! ====================
call .\gradlew.bat mergeJars -PmcVer="!version!" --no-daemon
echo ==================== Moving jar ==================== echo ==================== Moving jar ====================
move build\forgix\*.jar buildAllJars\ move Merged\*.jar buildAllJars\
) )
endlocal endlocal
-35
View File
@@ -1,35 +0,0 @@
@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
-24
View File
@@ -1,24 +0,0 @@
plugins {
id 'groovy-gradle-plugin'
}
repositories {
gradlePluginPortal()
mavenCentral()
maven { url = 'https://maven.wagyourtail.xyz/releases' } // Jvmdowngrader & unimined libs
maven { url = 'https://maven.outlands.top/releases' } // Hosts the kappa fork of unimined
maven { url = 'https://maven.wagyourtail.xyz/snapshots' } // The manifold gradle plugin we use
maven { url = 'https://maven.architectury.dev/' } // Minecraft mod libs
maven { url = 'https://maven.fabricmc.net/' } // Fabric
maven { url = 'https://maven.neoforged.net/releases/' } // NeoForge
maven { url = 'https://maven.minecraftforge.net/' } // Forge
maven { url = 'https://repo.spongepowered.org/repository/maven-public/' } // Hosts minecraft libs
maven { url = 'https://oss.sonatype.org/content/repositories/snapshots/' } // Hosts a few dependencies we use
}
dependencies {
implementation 'com.gradleup.shadow:shadow-gradle-plugin:9.0.0'
implementation 'xyz.wagyourtail.unimined:xyz.wagyourtail.unimined.gradle.plugin:1.4.18-kappa'
implementation 'xyz.wagyourtail:manifold-gradle:1.0.0-SNAPSHOT'
implementation 'xyz.wagyourtail.jvmdowngrader:xyz.wagyourtail.jvmdowngrader.gradle.plugin:1.3.4'
}
-594
View File
@@ -1,594 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
import org.apache.tools.zip.ZipEntry
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.
// IMPORTANT: unimined MUST be applied before shadow/jvmdowngrader
// so its afterEvaluate runs first and can modify configs.
plugins {
id 'java'
id 'maven-publish'
id 'xyz.wagyourtail.unimined'
id 'com.gradleup.shadow'
id 'xyz.wagyourtail.manifold'
id 'xyz.wagyourtail.jvmdowngrader'
}
def isNotCommonProject = project.name != "common"
if (isNotCommonProject) {
evaluationDependsOn(":common")
}
// ==================== Version Properties ====================
project.gradle.ext.getProperties().each { prop ->
rootProject.ext.set(prop.key, prop.value)
}
manifold {
version = rootProject.manifold_version
}
// ==================== Repositories ====================
repositories {
maven { url "https://libraries.minecraft.net/" }
mavenCentral()
maven { url "https://repo.enonic.com/public/" }
maven { url "https://maven.parchmentmc.org" }
maven { url "https://maven.architectury.dev" }
maven { url "https://jitpack.io" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
content { includeGroup "maven.modrinth" }
}
maven {
url "https://www.cursemaven.com"
content { includeGroup "curse.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 {
dirs "${rootDir}/mods/fabric"
content { includeGroup "fabric-mod" }
}
flatDir {
dirs "${rootDir}/mods/quilt"
content { includeGroup "quilt-mod" }
}
flatDir {
dirs "${rootDir}/mods/forge"
content { includeGroup "forge-mod" }
}
}
// ==================== Java Config ====================
tasks.withType(JavaCompile).configureEach {
options.release = rootProject.java_version as Integer
options.encoding = "UTF-8"
}
java {
sourceCompatibility = JavaVersion.toVersion(gradle.ext.java_version as Integer)
targetCompatibility = JavaVersion.toVersion(gradle.ext.java_version as Integer)
withSourcesJar()
}
// ==================== Loader-Only Config ====================
if (isNotCommonProject) {
base { archivesName = rootProject.mod_name }
rootProject.ext.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version
version = project.name + "-" + rootProject.versionStr
group = rootProject.maven_group
javadoc.title = rootProject.mod_name + "-" + project.name
tasks.withType(GenerateModuleMetadata).configureEach {
enabled = false
}
tasks.withType(Test).configureEach {
enabled = false
}
compileTestJava.enabled = false
tasks.withType(Sign).configureEach {
enabled = false
}
jar {
from "LICENSE.txt"
manifest {
attributes(
'Implementation-Title': rootProject.mod_name,
'Implementation-Version': rootProject.mod_version,
'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"
)
}
}
}
}
// ==================== Unimined Minecraft Config ====================
unimined.minecraft(sourceSets.main, true) {
version gradle.ext.minecraft_version
if (gradle.ext.minecraft_version.startsWith("1.")) { // 26.1+ doesn't use obfuscation
mappings {
if(gradle.ext.minecraft_version.startsWith("1.12.2")){
mcp("stable", "39-1.12")
}
else{
mojmap()
devNamespace "mojmap"
}
}
}
}
if (isNotCommonProject) {
// Mixin remapping and common project wiring
unimined.minecraft(sourceSets.main, true) {
mods.modImplementation {
mixinRemap {
reset()
enableBaseMixin()
enableMixinExtra()
}
// Some Fabric API modules ship AW in 'named' namespace instead of 'intermediary'
catchAWNamespaceAssertion()
}
}
dependencies {
implementation(project(":common"))
}
processResources {
from project(":common").sourceSets.main.resources
}
tasks.withType(JavaCompile).configureEach {
source(project(":common").sourceSets.main.allSource)
}
} else {
unimined.minecraft {
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")
configurations {
shadowMe
coreProjects
shadowMe.extendsFrom(coreProjects)
implementation.extendsFrom(shadowMe)
common
implementation.extendsFrom(common)
}
// ==================== Dependencies ====================
// Copy core's compileOnly deps so MC-provided deps are visible without redeclaring them.
project(":core").configurations.compileOnly.allDependencies.each { dep ->
if (!(dep instanceof ProjectDependency))
dependencies.add("compileOnly", dep)
}
dependencies {
// Manifold preprocessor & strings
annotationProcessor(manifold.module("preprocessor"))
// NightConfig: implementation in core (bundled) but Unimined strips it from compile classpath
compileOnly("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
// Core & API projects — bundled into shadow jar
coreProjects(project(":core"))
coreProjects(project(":api"))
// JOML: shadow for old MC versions that don't bundle it (core has it compileOnly already)
if (project.hasProperty("embed_joml") && embed_joml == "true")
shadowMe("org.joml:joml:${rootProject.joml_version}")
// Common project dependency
if (isNotCommonProject)
common(project(":common")) { transitive false }
}
// ==================== NativeTransformer ====================
class NativeTransformer implements ResourceTransformer {
private Predicate<String> fileMatcher
private Function<String, String> filePathMapper
private final HashMap<String, String> replacements = new HashMap()
private final HashMap<String, byte[]> rewrittenFiles = new HashMap()
private nativeRelocator
public File rootDir
void matchFiles(Predicate<String> matcher) {
fileMatcher = matcher
}
void mapPaths(Function<String, String> mapper) {
filePathMapper = mapper
}
void relocateNative(String target, String replacement) {
if (replacement.length() > target.length()) {
throw new GradleException("Length of value \"${replacement}\" exceeds the length of \"${target}\": ${replacement.length()} > ${target.length()}")
}
replacements.put(target, replacement)
}
@Override
boolean canTransformResource(@Nonnull FileTreeElement element) {
return fileMatcher != null && fileMatcher.test(element.relativePath.pathString)
}
@Override
void transform(@Nonnull TransformerContext context) {
byte[] content = context.inputStream.readAllBytes()
if (nativeRelocator == null) {
nativeRelocator = new NativeRelocator(rootDir.toPath().resolve("relocate_natives"))
}
try {
String path = filePathMapper != null
? filePathMapper.apply(context.path)
: context.path
content = nativeRelocator.processBinary(path, content, replacements)
rewrittenFiles.put(path, content)
}
catch (Throwable e) {
throw new GradleException("Failed to relocate", e)
}
}
@Override
boolean hasTransformedResource() { return !rewrittenFiles.isEmpty() }
@Override
void modifyOutputStream(@Nonnull ZipOutputStream os, boolean preserveFileTimestamps) {
for (Map.Entry<String, byte[]> rewrittenFile : rewrittenFiles.entrySet()) {
os.putNextEntry(new ZipEntry(rewrittenFile.key))
os.write(rewrittenFile.value)
}
}
}
// ==================== Shadow JAR (loaders only) ====================
if (isNotCommonProject) {
shadowJar {
configurations = [project.configurations.shadowMe]
def librariesLocation = "DistantHorizons.libraries"
// LZ4
relocate "net.jpountz", "${librariesLocation}.jpountz"
// SLF4J
relocate "org.slf4j", "${librariesLocation}.slf4j"
// SQLite
relocate "org.sqlite", "dh_sqlite", { exclude "org/sqlite/native/**" }
relocate "jdbc:sqlite", "jdbc:dh_sqlite"
transform(NativeTransformer) {
rootDir = project.rootDir
matchFiles { it.startsWith("org/sqlite") }
mapPaths { it.replace("org/sqlite", "dh_sqlite") }
relocateNative "org/sqlite", "dh_sqlite"
relocateNative "org_sqlite", "dh_1sqlite"
}
// ZStd
relocate "com.github.luben", "dhcomgithubluben"
relocate "libzstd-jni", "libzstd-jni_dh"
relocate "zstd-jni", "zstd-jni_dh"
transform(NativeTransformer) {
rootDir = project.rootDir
matchFiles { it.contains("libzstd-jni") && !it.contains("aix/ppc64") }
mapPaths { it.replace("libzstd-jni", "libzstd-jni_dh") }
relocateNative "com/github/luben", "dhcomgithubluben"
relocateNative "com_github_luben", "dhcomgithubluben"
}
// JOML (conditional)
if (project.hasProperty("embed_joml") && embed_joml == "true")
relocate "org.joml", "${librariesLocation}.joml"
// NightConfig
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
mergeServiceFiles()
}
afterEvaluate {
tasks.named("remapJar").configure {
dependsOn(shadowJar)
inputFile.set(shadowJar.archiveFile)
}
// Make run tasks use the shadow jar so relocated deps work in dev.
// Filter out jars bundled in the shadow jar, but keep jars that the loader also
// needs (e.g. NightConfig — DH relocates it, but NeoForge needs the original).
def shadowedPaths = configurations.shadowMe.resolve().collect { it.path }.toSet()
def loaderPaths = configurations.minecraftLibraries.resolve().collect { it.path }.toSet()
tasks.withType(JavaExec).configureEach { runTask ->
dependsOn(shadowJar)
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
def isClient = runTask.name.toLowerCase().contains("client")
runTask.workingDir = rootProject.file("run/${isClient ? 'client' : 'server'}")
// Minecraft automatically has G1GC args present,
// remove them so we can use ZGC instead
def filteredArgs = runTask.jvmArgs.findAll { arg ->
!arg.startsWith("-XX:+UseG1GC") &&
!arg.startsWith("-XX:G1") &&
!arg.startsWith("-XX:MaxGCPauseMillis")
}
runTask.jvmArgs = filteredArgs
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(
"-Dio.netty.leakDetection.level=advanced",
// TODO only use for modern java versions
"-XX:+UseZGC",
// TODO don't use for even more modern-er java versions
//"-XX:+ZGenerational",
rootProject.minecraftMemoryJavaArg,
)
if (isClient)
{
runTask.jvmArgs(
"-Dminecraft.api.auth.host=https://nope.invalid",
"-Dminecraft.api.account.host=https://nope.invalid",
"-Dminecraft.api.session.host=https://nope.invalid",
"-Dminecraft.api.services.host=https://nope.invalid",
)
runTask.args(
// use a consistent username for easier debugging in a given world (vs randomly teleporting to a new user each time the game boots)
"--username", "Dev",
// "--renderDebugLabels" is a Mojang command to show render names in RenderDoc
"--renderDebugLabels"
)
// 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
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) }
}
}
// ==================== Process Resources (loaders only) ====================
if (isNotCommonProject) {
processResources {
def resourceTargets = [
"build_info.json",
"fabric.mod.json",
"mcmod.info",
"quilt.mod.json",
"META-INF/mods.toml",
"META-INF/neoforge.mods.toml",
]
// 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\"")
}
quilt_contributors.reverse()
try {
if (rootProject.infoGitCommit == "null")
rootProject.ext.infoGitCommit = 'git rev-parse --verify HEAD'.execute().text.trim()
if (rootProject.infoGitBranch == "null")
rootProject.ext.infoGitBranch = 'git symbolic-ref --short HEAD'.execute().text.trim()
} catch (Exception e) {
rootProject.ext.infoGitCommit = "Git not found"
rootProject.ext.infoGitBranch = "Git not found"
}
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,
issues : rootProject.mod_issues,
discord : rootProject.mod_discord,
minecraft_version : rootProject.minecraft_version,
accessWidenerVersion : rootProject.accessWidenerVersion,
compatible_minecraft_versions: rootProject.compatible_minecraft_versions,
compatible_forgemc_versions : compatible_forgemc_versions,
java_version : rootProject.java_version,
quilt_contributors : "{" + quilt_contributors.join(", ") + "}",
info_git_commit : rootProject.infoGitBranch,
info_git_branch : rootProject.infoGitCommit,
info_build_source : rootProject.infoBuildSource,
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
replaceProperties.put "project", project
filesMatching(resourceTargets) {
expand replaceProperties
}
// Remove unused access wideners
exclude { file ->
if ((file.name.contains(".distanthorizons.accesswidener") && file.name != "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener")) {
return true
}
return false
}
}
// ==================== Resource Copy Tasks ====================
// task copyCommonLoaderResources(type: Copy) {
// from project(":common").file("src/main/resources/${rootProject.accessWidenerVersion}.distanthorizons.accesswidener")
// into(file(project.file("build/resources/main")))
// rename "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
// }
task copyCoreResources(type: Copy) {
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 ->
def text = value.toString().replaceAll(/%(?!((\d+)\$)?s|%)/, "%%").replace("\n", "\\n")
writer.writeLine("${key}=${text}")
}
}
}
}
// ==================== JVMDowngrader ====================
jvmdg.downgradeTo = JavaVersion.toVersion(rootProject.java_version)
downgradeJar.archiveClassifier.set(null)
shadeDowngradedApi.archiveClassifier.set(null)
}
-56
View File
@@ -1,56 +0,0 @@
plugins {
id 'java'
}
// Transfer version properties from settings.gradle to project
project.gradle.ext.getProperties().each { prop ->
rootProject.ext.set(prop.key, prop.value)
}
// Version string for archives
rootProject.ext.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version
rootProject.allprojects {
version = (it == rootProject ? "" : it.name + "-") + rootProject.versionStr
group = rootProject.maven_group
// Custom javadoc tags for all subprojects
plugins.withType(JavaPlugin) {
javadoc {
options.tags(
'todo:X"',
'apiNote:a:API Note:',
'implSpec:a:Implementation Requirements:',
'implNote:a:Implementation Note:'
)
}
}
}
// Create build.properties with preprocessor definitions
def writePreprocessorDefinitions() {
StringBuilder sb = new StringBuilder()
sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n")
gradle.ext.mcVers.eachWithIndex { ver, idx ->
sb.append("MC_${ver.replace('.', '_')}=${idx}\n")
if (gradle.ext.mcIndex == idx)
sb.append("MC_VER=${idx}\n")
}
if (rootProject.mod_version.toLowerCase().contains("dev")) {
sb.append("DEV_BUILD=\n")
}
new File(rootDir, "build.properties").text = sb.toString()
}
writePreprocessorDefinitions()
// Wire JVMDowngrader to process remapped jars
gradle.projectsEvaluated {
rootProject.subprojects.each {
if (it.tasks.findByName('remapJar') == null) return
it.tasks.downgradeJar.inputFile = it.tasks.remapJar.archiveFile
it.tasks.jar.finalizedBy(it.tasks.remapJar)
it.tasks.remapJar.finalizedBy(it.tasks.shadeDowngradedApi)
}
}
@@ -1,15 +0,0 @@
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")
}
}
}
@@ -1,13 +0,0 @@
plugins {
id 'dh-loader'
}
unimined.minecraft {
fabric {
loader gradle.ext.fabric_loader_version
accessWidener project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
}
}
runClient.javaLauncher = null
runServer.javaLauncher = null
@@ -1,17 +0,0 @@
plugins {
id 'dh-loader'
}
def awFile = project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
unimined.minecraft {
forge {
loader gradle.ext.forge_version
useToolchains = false
mixinConfig("DistantHorizons.forge.mixins.json")
accessTransformer aw2at(awFile)
}
}
runClient.javaLauncher = null
runServer.javaLauncher = null
@@ -1,16 +0,0 @@
plugins {
id 'dh-loader'
}
def awFile = project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
unimined.minecraft {
neoForged {
loader gradle.ext.neoforge_version
useToolchains = false
accessTransformer aw2at(awFile)
}
}
runClient.javaLauncher = null
runServer.javaLauncher = null
-214
View File
@@ -1,214 +0,0 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
class NativeRelocator
{
private final Path rootDirectory;
private final Path cacheRoot;
/**
* Initializes the NativeRelocator by preparing the environment if necessary.
* Executes the appropriate preparation script based on the OS.
*/
NativeRelocator(Path rootDirectory)
{
this.rootDirectory = rootDirectory;
this.cacheRoot = this.rootDirectory.resolve("cache");
}
private void prepare() throws Exception
{
if (this.rootDirectory.resolve(".venv").toFile().exists())
{
return;
}
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.directory(this.rootDirectory.toFile());
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win"))
{
processBuilder.command("powershell", "-ExecutionPolicy", "Bypass", "./prepare.ps1");
}
else if (os.contains("nix")
|| os.contains("nux")
|| os.contains("mac")
|| os.contains("freebsd"))
{
processBuilder.command("./prepare.sh");
}
else
{
throw new IllegalStateException("Unsupported operating system: " + os);
}
Process process = processBuilder.start();
CompletableFuture<Void> outputFuture = readOutputStreams(process);
int exitCode = process.waitFor();
outputFuture.get();
if (exitCode != 0)
{
throw new Exception("Prepare failed: " + exitCode);
}
}
/**
* Reads and prints the output and error streams of a process asynchronously.
*
* @param process The process whose streams should be read.
* @return A CompletableFuture that completes once all output has been processed.
*/
private static CompletableFuture<Void> readOutputStreams(Process process)
{
return CompletableFuture.runAsync(() -> {
try
{
while (process.isAlive() || process.getInputStream().available() > 0 || process.getErrorStream().available() > 0)
{
if (process.getInputStream().available() > 0)
{
byte[] data = new byte[process.getInputStream().available()];
//noinspection ResultOfMethodCallIgnored
process.getInputStream().read(data);
System.out.write(data);
}
if (process.getErrorStream().available() > 0)
{
byte[] data = new byte[process.getErrorStream().available()];
//noinspection ResultOfMethodCallIgnored
process.getErrorStream().read(data);
System.err.write(data);
}
//noinspection BusyWait
Thread.sleep(100);
}
}
catch (Throwable ignored)
{
}
});
}
/**
* Replaces occurrences of a target string in a byte array, ensuring null termination.
*
* @param byteArray The byte array where replacements should occur.
* @param target The string to replace.
* @param replacement The replacement string (must not be longer than the target).
* @throws IllegalArgumentException if the replacement is longer than the target.
*/
private void replaceInNullTerminatedStrings(byte[] byteArray, String target, String replacement)
{
if (target.length() < replacement.length())
{
throw new IllegalArgumentException("Replacement must be the same length or shorter than the target.");
}
byte[] targetBytes = target.getBytes(StandardCharsets.US_ASCII);
byte[] replacementBytes = replacement.getBytes(StandardCharsets.US_ASCII);
byte nullByte = 0;
for (int endPos = 0; endPos < byteArray.length - targetBytes.length - 1; endPos++)
{
int startPos = endPos;
int targetPos = 0;
while (targetPos < targetBytes.length && byteArray[endPos] == targetBytes[targetPos])
{
targetPos++;
endPos++;
}
if (targetPos == targetBytes.length)
{
System.arraycopy(replacementBytes, 0, byteArray, startPos, replacementBytes.length);
startPos = startPos + replacementBytes.length;
while (byteArray[endPos] != nullByte)
{
byteArray[startPos] = byteArray[endPos];
endPos++;
startPos++;
}
byteArray[startPos] = nullByte;
}
}
}
/**
* Runs an external script to fix a modified binary and returns the processed content.
*
* @param outputFilePath Path to store the processed binary.
* @param content The original binary content.
* @return The modified binary content.
* @throws Exception if the process execution fails.
*/
public byte[] fixModifiedBinary(Path outputFilePath, byte[] content) throws Exception
{
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.directory(this.rootDirectory.toFile());
processBuilder.command(
this.rootDirectory.resolve(".venv/Scripts").toFile().exists()
? this.rootDirectory.resolve(".venv/Scripts/python.exe").toString()
: this.rootDirectory.resolve(".venv/bin/python").toString(),
"./fix_modified_binary.py",
outputFilePath.toString()
);
Process process = processBuilder.start();
CompletableFuture<Void> outputFuture = readOutputStreams(process);
process.getOutputStream().write(content);
process.getOutputStream().close();
int exitCode = process.waitFor();
outputFuture.get();
if (exitCode != 0)
{
throw new Exception("Process failed: " + exitCode);
}
return Files.readAllBytes(outputFilePath);
}
/**
* Processes a binary file, applying string replacements and fixing modifications.
*
* @param outputPath The output file path relative to the cache directory.
* @param content The binary content to process.
* @param replacements A map of string replacements to apply.
* @return The modified binary content.
* @throws Exception if processing fails.
*/
public byte[] processBinary(String outputPath, byte[] content, Map<String, String> replacements) throws Exception
{
Path outputFilePath = this.cacheRoot.resolve(outputPath);
//noinspection ResultOfMethodCallIgnored
outputFilePath.getParent().toFile().mkdirs();
if (outputFilePath.toFile().exists())
{
return Files.readAllBytes(outputFilePath);
}
System.out.println("Relocating to " + outputPath + "...");
this.prepare();
for (Map.Entry<String, String> replacement : replacements.entrySet())
{
this.replaceInNullTerminatedStrings(content, replacement.getKey(), replacement.getValue());
}
return this.fixModifiedBinary(outputFilePath, content);
}
}
-41
View File
@@ -1,41 +0,0 @@
@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
@@ -1,48 +0,0 @@
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) }
}
@@ -1,214 +0,0 @@
/*
* 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);
}
//==============//
// 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
}
@@ -1,147 +0,0 @@
/*
* 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();
}
}
@@ -1,136 +0,0 @@
/*
* 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
}
@@ -1,181 +0,0 @@
/*
* 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 && event.getChunk().dirty)
{
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
}
@@ -1,56 +0,0 @@
/*
* 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) { }
}
@@ -1,82 +0,0 @@
/*
* 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 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;
}
MinecraftRenderWrapper renderWrapper = (MinecraftRenderWrapper)SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
renderWrapper.setLightmapId(lightmapTexture.getGlTextureId());
}
@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;
}
}
}
@@ -1,24 +0,0 @@
package com.seibel.distanthorizons.cleanroom.mixins.client;
import com.seibel.distanthorizons.common.commonMixins.DhUpdateScreenBase;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.client.Minecraft;
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(Minecraft.class)
public class MixinMinecraft
{
@Inject(method = "init", at = @At("TAIL"))
private void onInit(CallbackInfo ci)
{
if(Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() && !ModInfo.IS_DEV_BUILD) // weird lib class not found error can occur if we don't check if we are in dev
{
DhUpdateScreenBase.tryShowUpdateScreenAndRunAutoUpdateStartup(null);
}
}
}
@@ -1,46 +0,0 @@
/*
* 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();
}
}
@@ -1,83 +0,0 @@
/*
* 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();
}
}
}
@@ -1,68 +0,0 @@
/*
* 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.DhMat4f;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.entity.Entity;
import net.minecraft.util.BlockRenderLayer;
import org.lwjgl.opengl.GL32;
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];
GL32.glGetFloatv(GL32.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
ClientApi.RENDER_STATE.mcProjectionMatrix = new DhMat4f(mcProjMatrixRaw);
ClientApi.RENDER_STATE.mcProjectionMatrix.transpose();
float[] mcModelViewRaw = new float[16];
GL32.glGetFloatv(GL32.GL_MODELVIEW_MATRIX, mcModelViewRaw);
ClientApi.RENDER_STATE.mcModelViewMatrix = new DhMat4f(mcModelViewRaw);
ClientApi.RENDER_STATE.mcModelViewMatrix.transpose();
ClientApi.RENDER_STATE.partialTickTime = (float) partialTicks;
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, this.world);
ClientApi.INSTANCE.renderLods();
//Some 1.12.2 rendering mods breaks if we don't unbind buffers
GL32.glBindVertexArray(0);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, 0);
GL32.glBindBuffer(GL32.GL_ELEMENT_ARRAY_BUFFER, 0);
GL32.glUseProgram(0);
}
}
}
@@ -1,17 +0,0 @@
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);
}
}
@@ -1,66 +0,0 @@
/*
* 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; }
}
@@ -1,52 +0,0 @@
/*
* 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();
}
}
@@ -1,20 +0,0 @@
{
"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.MixinMinecraft",
"client.MixinNetHandlerPlayClient",
"client.MixinOptionsScreen",
"client.MixinRenderGlobal"
]
}
@@ -1,11 +0,0 @@
{
"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
@@ -1,12 +0,0 @@
[{
"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
@@ -1,6 +0,0 @@
{
"pack": {
"description": "${mod_name} Resources",
"pack_format": 3
}
}
+38 -2
View File
@@ -1,3 +1,39 @@
plugins {
id 'dh-loader' // temporary fix for broken spongepowered version
buildscript {
configurations.configureEach {
resolutionStrategy {
force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82'
}
}
} }
plugins {
id "org.spongepowered.gradle.vanilla" version "0.2.1-SNAPSHOT"
}
minecraft {
accessWideners(project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener"))
version(rootProject.minecraft_version)
}
dependencies {
// So mixins can be written in common
compileOnly group:'org.spongepowered', name:'mixin', version:'0.8.5'
}
publishing {
publications {
mavenCommon(MavenPublication) {
artifactId = rootProject.mod_readable_name
from components.java
}
}
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
repositories {
// Add repositories to publish to here.
}
}
@@ -1,133 +1,97 @@
package com.seibel.distanthorizons.common; package com.seibel.distanthorizons.common;
import com.seibel.distanthorizons.api.enums.config.EDhApiMcRenderingFadeMode; import com.mojang.brigadier.CommandDispatcher;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent; 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.DependencySetup;
import com.seibel.distanthorizons.common.wrappers.gui.DhDebugScreenEntry; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper; import com.seibel.distanthorizons.core.api.internal.SharedApi;
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.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigHandler; import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler; import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
import com.seibel.distanthorizons.core.jar.ModJarInfo; import com.seibel.distanthorizons.core.jar.ModJarInfo;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.render.renderer.StubDebugWireframeRenderer;
import com.seibel.distanthorizons.common.wrappers.gui.NativeDialogUtil;
import com.seibel.distanthorizons.core.util.ThreadUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.dedicated.DedicatedServer;
import com.seibel.distanthorizons.core.logging.DhLogger; import org.apache.logging.log4j.Logger;
import java.util.concurrent.CompletableFuture; import java.lang.invoke.MethodHandles;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; 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 * Base for all mod loader initializers
* and handles most setup. * and handles most setup.
*/ */
public abstract class AbstractModInitializer public abstract class AbstractModInitializer
{ {
protected static final DhLogger LOGGER = new DhLoggerBuilder().build(); protected static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
private CommandInitializer commandInitializer; private CommandDispatcher<CommandSourceStack> commandDispatcher;
//==================// //==================//
// abstract methods // // abstract methods //
//==================// //==================//
//region
protected abstract void createInitialSharedBindings(); protected abstract void createInitialBindings();
protected abstract void createInitialClientBindings();
protected abstract IEventProxy createClientProxy(); protected abstract IEventProxy createClientProxy();
protected abstract IEventProxy createServerProxy(boolean isDedicated); protected abstract IEventProxy createServerProxy(boolean isDedicated);
protected abstract void initializeModCompat(); protected abstract void initializeModCompat();
#if MC_VER > MC_1_12_2
protected abstract void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler); protected abstract void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler);
#endif
protected abstract void subscribeClientStartedEvent(Runnable eventHandler); protected abstract void subscribeClientStartedEvent(Runnable eventHandler);
protected abstract void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler); protected abstract void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler);
protected abstract void runDelayedSetup(); protected abstract void runDelayedSetup();
//endregion
//===================// //===================//
// initialize events // // initialize events //
//===================// //===================//
//region
public void onInitializeClient() public void onInitializeClient()
{ {
DependencySetup.createClientBindings(); DependencySetup.createClientBindings();
this.createInitialClientBindings();
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " client, firing DhApiBeforeDhInitEvent..."); LOGGER.info("Initializing " + ModInfo.READABLE_NAME);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null); ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
this.startup(); this.startup();
this.logBuildInfo(); this.printModInfo(true);
this.createClientProxy().registerEvents(); this.createClientProxy().registerEvents();
this.createServerProxy(false).registerEvents(); this.createServerProxy(false).registerEvents();
this.initializeModCompat(); this.initializeModCompat();
LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
// Client uses config for auto-updater, so it's initialized here instead of post-init stage // Client uses config for auto-updater, so it's initialized here instead of post-init stage
this.initConfig(); this.initConfig();
logIncompatibilityWarnings(); // needs to be called after config loading
setUnsupportedConfigsBasedOnMcVersion();
Initializer.postConfigInit();
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
#if MC_VER < MC_1_21_9
// debug screen rendering handled via a mixin
#else
DhDebugScreenEntry.register();
#endif
this.subscribeClientStartedEvent(this::postInit); this.subscribeClientStartedEvent(this::postInit);
this.subscribeClientStartedEvent(this::postClientInit);
} }
public void onInitializeServer() public void onInitializeServer()
{ {
DependencySetup.createServerBindings(); DependencySetup.createServerBindings();
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " server, firing DhApiBeforeDhInitEvent event..."); LOGGER.info("Initializing " + ModInfo.READABLE_NAME);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null); ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
this.startup(); this.startup();
this.logBuildInfo(); this.printModInfo(false);
// This prevents returning uninitialized Config values, // This prevents returning uninitialized Config values,
// resulting from a circular reference mid-initialization in a static class // resulting from a circular reference mid-initialization in a static class
@@ -136,62 +100,43 @@ public abstract class AbstractModInitializer
this.createServerProxy(true).registerEvents(); this.createServerProxy(true).registerEvents();
this.initializeModCompat(); LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized, adding event subscribers..."); this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandDispatcher = dispatcher; });
#if MC_VER > MC_1_12_2
this.commandInitializer = new CommandInitializer();
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer.initCommands(dispatcher); });
#endif
this.subscribeServerStartingEvent(server -> this.subscribeServerStartingEvent(server ->
{ {
MinecraftServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server; MinecraftDedicatedServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server;
this.initConfig(); this.initConfig();
Initializer.postConfigInit();
this.postInit(); this.postInit();
this.postServerInit(); this.initCommands();
#if MC_VER > MC_1_12_2
this.commandInitializer.onServerReady();
#endif
this.checkForUpdates(); LOGGER.info("Dedicated 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);
}); });
} }
//endregion
//===========================// //===========================//
// inner initializer methods // // inner initializer methods //
//===========================// //===========================//
//region
private void startup() private void startup()
{ {
DependencySetup.createSharedBindings(); DependencySetup.createSharedBindings();
Initializer.preConfigInit(); SharedApi.init();
this.createInitialSharedBindings(); this.createInitialBindings();
} }
private void logBuildInfo() private void printModInfo(boolean printGitInfo)
{ {
LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION); LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
// if the build is stable the branch/commit/etc shouldn't be needed if (printGitInfo)
if (ModInfo.IS_DEV_BUILD)
{ {
// Useful for dev builds
LOGGER.info("DH Branch: " + ModJarInfo.Git_Branch); LOGGER.info("DH Branch: " + ModJarInfo.Git_Branch);
LOGGER.info("DH Commit: " + ModJarInfo.Git_Commit); LOGGER.info("DH Commit: " + ModJarInfo.Git_Commit);
LOGGER.info("DH Jar Build Source: " + ModJarInfo.Build_Source); LOGGER.info("DH Jar Build Source: " + ModJarInfo.Build_Source);
@@ -206,249 +151,32 @@ public abstract class AbstractModInitializer
//noinspection unchecked //noinspection unchecked
ModAccessorInjector.INSTANCE.bind((Class<? extends IModAccessor>) accessorClass, accessorConstructor.get()); ModAccessorInjector.INSTANCE.bind((Class<? extends IModAccessor>) accessorClass, accessorConstructor.get());
} }
else
{
LOGGER.debug("Skipping mod compatibility accessor for: ["+modId+"]");
}
} }
private void initConfig() private void initConfig()
{ {
ConfigHandler.tryRunFirstTimeSetup(); ConfigBase.INSTANCE = new ConfigBase(ModInfo.ID, ModInfo.NAME, Config.class, 2);
Config.completeDelayedSetup(); Config.completeDelayedSetup();
DhLogger.runDelayedConfigSetup();
}
private void checkForUpdates()
{
if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get())
{
if (Config.Client.Advanced.AutoUpdater.enableSilentUpdates.get())
{
LOGGER.info("Silent updates are not allowed for dedicated servers; force disabling.");
Config.Client.Advanced.AutoUpdater.enableSilentUpdates.set(false);
}
SelfUpdater.onStart();
}
} }
private void postInit() private void postInit()
{ {
LOGGER.info("Running Delayed setup..."); LOGGER.info("Post-Initializing Mod");
this.runDelayedSetup(); this.runDelayedSetup();
LOGGER.info("Mod Post-Initialized");
if (ConfigHandler.INSTANCE == null)
{
throw new IllegalStateException("Config was not initialized. Make sure to call LodCommonMain.initConfig() before calling this method.");
}
LOGGER.info("Delayed setup complete, firing DhApiAfterDhInitEvent event...");
// should be fired after all delayed setup so singletons and config can be accessed
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
} }
private void postClientInit() private void initCommands() { /* currently unimplemented */ }
{
CompletableFuture<Void> future = new CompletableFuture<>();
// This method may be called from either the render thread,
// or some other random setup thread depending on the mod loader.
// In order to avoid confusion/inconsistent problems, we're always going
// to run setup on our own thread.
Thread dhSetupThread = new Thread(() ->
{
try
{
DependencySetup.setRenderingApiBindings();
}
catch (Exception e)
{
NativeDialogUtil.showDialog(ModInfo.READABLE_NAME, e.getMessage(), "ok", "error");
MinecraftClientWrapper.INSTANCE.crashMinecraft(e.getMessage(), e);
future.completeExceptionally(e);
}
finally
{
future.complete(null);
}
});
dhSetupThread.setName(ThreadUtil.THREAD_NAME_PREFIX + "PostClientInit Thread");
dhSetupThread.start();
future.join();
}
private void postServerInit() { SingletonInjector.INSTANCE.bind(AbstractDebugWireframeRenderer.class, new StubDebugWireframeRenderer()); }
//endregion
//======================//
// compatibility checks //
//======================//
//region
/**
* Some mods will work with a few tweaks
* or will partially work but have some known issues we can't solve.
* This method will log (and display to chat if enabled)
* these warnings and potential fixes.
*/
private static void logIncompatibilityWarnings()
{
boolean showChatWarnings = Config.Common.Logging.Warning.showModCompatibilityWarningsOnStartup.get();
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
String startingString = "Partially Incompatible Distant Horizons mod detected: ";
// Alex's caves
//region
if (modChecker.isModLoaded("alexscaves"))
{
// There've been a few reports about this mod breaking DH at a few different points in time
// the fixes for said breakage changes depending on the version so unfortunately
// all we can do is log a warning so the user can handle it.
if (showChatWarnings)
{
String message =
MinecraftTextFormat.ORANGE + "Distant Horizons: Alex's Cave detected." + MinecraftTextFormat.CLEAR_FORMATTING +
"You may have to change Alex's config for DH to render. ";
ClientApi.INSTANCE.showChatMessageNextFrame(message);
}
LOGGER.warn(startingString + "[Alex's Caves] may require some config changes in order to render Distant Horizons correctly.");
}
//endregion
// William Wythers' Overhauled Overworld (WWOO)
//region
if (modChecker.isModLoaded("wwoo"))
{
// WWOO has a bug with it's world gen that can't be fixed by DH or WWOO
// (at least that is what James learned after talking with WWOO)
// WWOO will cause grid lines to appear in the world when DH generates the chunks
// this might be due to how WWOO uses features for everything when generating
// and said features don't always get to the edge of said chunks.
String wwooWarning = "LODs generated by DH may have grid lines between sections. Disabling either WWOO or DH's distant generator will fix the problem.";
if (showChatWarnings)
{
String message =
MinecraftTextFormat.ORANGE + "Distant Horizons: WWOO detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
wwooWarning;
ClientApi.INSTANCE.showChatMessageNextFrame(message);
}
LOGGER.warn(startingString + "[WWOO] "+ wwooWarning);
}
//endregion
// Chunky //
//region
boolean chunkyPresent = false;
try
{
Class.forName("org.popcraft.chunky.api.ChunkyAPI");
chunkyPresent = true;
}
catch (ClassNotFoundException ignore) { }
if (chunkyPresent)
{
// Chunky can generate chunks faster than DH can process them,
// causing holes in the LODs.
// Generally it's better and faster to use DH's world generator.
String chunkyWarning = "Chunky can cause DH LODs to have holes " +
"since Chunky can generate chunks faster than DH can process them. \n" +
"Using DH's distant generator instead of chunky or increasing DH's CPU thread count can resolve the issue.";
if (showChatWarnings)
{
String message =
MinecraftTextFormat.ORANGE + "Distant Horizons: Chunky detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
chunkyWarning;
ClientApi.INSTANCE.showChatMessageNextFrame(message);
}
LOGGER.warn(startingString + "[Chunky] "+ chunkyWarning);
}
//endregion
// iris //
//region
IIrisAccessor iris = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
if (iris != null)
{
// get the currently selected rendering API
EDhApiRenderingEngine renderApi = Config.Client.Advanced.Graphics.Experimental.renderingEngine.get();
if (renderApi == EDhApiRenderingEngine.AUTO)
{
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
renderApi = versionConstants.getDefaultRenderingEngine();
}
// Iris only supports native OpenGL
if (renderApi != EDhApiRenderingEngine.OPEN_GL)
{
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");
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
String errorMessage = "loading Distant Horizons. "+irisUnsupportedMessage;
String exceptionError = "Distant Horizons conditional mod config Exception";
mc.crashMinecraft(errorMessage, new Exception(exceptionError));
}
}
//endregion
}
/**
* 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
//================// //================//
// helper classes // // helper classes //
//================// //================//
//region
public interface IEventProxy public interface IEventProxy
{ {
void registerEvents(); void registerEvents();
} }
//endregion
} }
@@ -1,165 +0,0 @@
package com.seibel.distanthorizons.common;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent;
import com.seibel.distanthorizons.core.network.event.internal.ProtocolErrorInternalEvent;
import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
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_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
import java.io.IOException;
import java.util.Objects;
public abstract class AbstractPluginPacketSender implements IPluginPacketSender
{
private static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logNetworkEventToFile)
.build();
#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);
#else
public static final Identifier WRAPPER_PACKET_RESOURCE = Identifier.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
#endif
// "Forge byte" is an unused packet ID. We have our own system which works with all mod loaders,
// so we're just accounting for it by reading the protocol version as a byte instead of a short in Forge, to keep cross-loader compatibility
private final boolean forgeByteInProtocolVersion;
public AbstractPluginPacketSender() { this(false); }
public AbstractPluginPacketSender(boolean forgeByteInProtocolVersion)
{
this.forgeByteInProtocolVersion = forgeByteInProtocolVersion;
}
@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;
try
{
in.markReaderIndex();
int protocolVersion = this.forgeByteInProtocolVersion ? in.readByte() : in.readShort();
if (protocolVersion != ModInfo.PROTOCOL_VERSION)
{
return new IncompatibleMessageInternalEvent(protocolVersion);
}
message = MessageRegistry.INSTANCE.createMessage(in.readUnsignedShort());
message.decode(in);
if (in.isReadable())
{
throw new IOException("Buffer has not been fully read");
}
return message;
}
catch (Exception e)
{
in.resetReaderIndex();
LOGGER.error("Failed to decode message", e);
LOGGER.error("Buffer: ["+in+"]");
LOGGER.error("Buffer contents: ["+ByteBufUtil.hexDump(in)+"]");
return new ProtocolErrorInternalEvent(e, message, true);
}
finally
{
// Prevent connection crashing if not entire buffer has been read
in.readerIndex(in.writerIndex());
}
}
#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);
if (this.forgeByteInProtocolVersion)
{
out.writeByte(ModInfo.PROTOCOL_VERSION);
}
else
{
out.writeShort(ModInfo.PROTOCOL_VERSION);
}
try
{
out.markWriterIndex();
out.writeShort(MessageRegistry.INSTANCE.getMessageId(message));
message.encode(out);
}
catch (Exception e)
{
LOGGER.error("Failed to encode message", e);
LOGGER.error("Message: ["+message+"]");
message.getSession().tryHandleMessage(new ProtocolErrorInternalEvent(e, message, false));
// Encode close reason message instead
out.resetWriterIndex();
message = new CloseReasonMessage("Internal error on other side");
out.writeShort(MessageRegistry.INSTANCE.getMessageId(message));
message.encode(out);
}
}
}
@@ -1,39 +0,0 @@
package com.seibel.distanthorizons.common;
#if MC_VER >= MC_1_20_6
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public record CommonPacketPayload(@Nullable AbstractNetworkMessage message) implements CustomPacketPayload
{
public static final Type<CommonPacketPayload> TYPE = new Type<>(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE);
private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
@NotNull
@Override
public Type<? extends CustomPacketPayload> type() { return TYPE; }
public static class Codec implements StreamCodec<FriendlyByteBuf, CommonPacketPayload>
{
@NotNull
@Override
public CommonPacketPayload decode(@NotNull FriendlyByteBuf in)
{ return new CommonPacketPayload(PACKET_SENDER.decodeMessage(in)); }
@Override
public void encode(@NotNull FriendlyByteBuf out, CommonPacketPayload payload)
{ PACKET_SENDER.encodeMessage(out, payload.message()); }
}
}
#endif
@@ -1,107 +0,0 @@
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;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import net.minecraft.commands.CommandSourceStack;
#if MC_VER >= MC_1_19_2
import net.minecraft.network.chat.Component;
import java.util.Objects;
#else // < 1.19.2
import net.minecraft.network.chat.TranslatableComponent;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
#endif
/**
* Abstract class providing common functionality for DH's commands.
*/
public abstract class AbstractCommand
{
public abstract LiteralArgumentBuilder<CommandSourceStack> buildCommand();
/**
* Sends a success response to the player with the given text.
*
* @param commandContext The command context to send the response to.
* @param text The text to display in the success message.
* @return 1, indicating that the command was successful.
*/
protected int sendSuccessResponse(CommandContext<CommandSourceStack> commandContext, String text, boolean notifyAdmins)
{
#if MC_VER >= MC_1_20_1
commandContext.getSource().sendSuccess(() -> Component.literal(text), notifyAdmins);
#elif MC_VER >= MC_1_19_2
commandContext.getSource().sendSuccess(Component.literal(text), notifyAdmins);
#else
commandContext.getSource().sendSuccess(new TranslatableComponent(text), notifyAdmins);
#endif
return 1;
}
/**
* Sends a failure response to the player with the given text.
*
* @param commandContext The command context to send the response to.
* @param text The text to display in the failure message.
* @return 1, indicating that the command was successful.
*/
protected int sendFailureResponse(CommandContext<CommandSourceStack> commandContext, String text)
{
#if MC_VER >= MC_1_20_1
commandContext.getSource().sendFailure(Component.literal(text));
#elif MC_VER >= MC_1_19_2
commandContext.getSource().sendFailure(Component.literal(text));
#else
commandContext.getSource().sendFailure(new TranslatableComponent(text));
#endif
return 1;
}
/**
* Gets the server player from a command context.
*
* @param commandContext The command context to get the server player from.
* @return The server player wrapper for the player who sent the command.
*/
protected IServerPlayerWrapper getSourcePlayer(CommandContext<CommandSourceStack> commandContext) #if MC_VER < MC_1_19_2 throws CommandSyntaxException #endif
{
#if MC_VER >= MC_1_19_2
return ServerPlayerWrapper.getWrapper(Objects.requireNonNull(commandContext.getSource().getPlayer()));
#else
return ServerPlayerWrapper.getWrapper(commandContext.getSource().getPlayerOrException());
#endif
}
/**
* Checks if the source of a command is a player.
*
* @param source The source of the command to check.
* @return True if the source is a player, false otherwise.
*/
protected boolean isPlayerSource(CommandSourceStack source)
{
#if MC_VER >= MC_1_19_2
return source.isPlayer();
#else
try
{
source.getPlayerOrException();
return true;
}
catch (CommandSyntaxException e)
{
return false;
}
#endif
}
}
#endif
@@ -1,162 +0,0 @@
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;
#if MC_VER <= MC_1_21_10
#else
import net.minecraft.server.permissions.PermissionCheck;
import net.minecraft.server.permissions.Permissions;
#endif
public class CommandInitializer
{
private boolean serverReady = false;
#if MC_VER <= MC_1_21_10
private static final int REQUIRED_PERMISSION_LEVEL = 4;
#else
private static final PermissionCheck COMMAND_PERMISSION_CHECK = new PermissionCheck.Require(Permissions.COMMANDS_OWNER);
#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.
*/
@Nullable
private CommandDispatcher<CommandSourceStack> commandDispatcher;
/**
* Notify the command initializer that the game is ready to accept commands.
* If {@link CommandInitializer#initCommands(CommandDispatcher)} has been fired before it was ready, it will also initialize the commands.
*/
public void onServerReady()
{
this.serverReady = true;
if (this.commandDispatcher != null)
{
this.initCommands(this.commandDispatcher);
this.commandDispatcher = null;
}
}
/**
* Initializes all available commands.
* If the game is not ready yet, it stores the dispatcher to initialize the commands later.
*
* @param commandDispatcher The command dispatcher to register commands to.
*/
public void initCommands(CommandDispatcher<CommandSourceStack> commandDispatcher)
{
if (!this.serverReady)
{
this.commandDispatcher = commandDispatcher;
return;
}
LiteralArgumentBuilder<CommandSourceStack> builder = literal("dh")
.requires((source) ->
{
#if MC_VER <= MC_1_21_10
return source.hasPermission(REQUIRED_PERMISSION_LEVEL);
#else
return COMMAND_PERMISSION_CHECK.check(source.permissions());
#endif
});
builder.then(new ConfigCommand().buildCommand());
builder.then(new DebugCommand().buildCommand());
builder.then(new PregenCommand().buildCommand());
if (DEBUG_CODEC_CRASH_MESSAGE)
{
builder.then(new CrashCommand().buildCommand());
}
commandDispatcher.register(builder);
}
#endif
}
@@ -1,226 +0,0 @@
package com.seibel.distanthorizons.common.commands;
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;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.ToIntBiFunction;
/**
* 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),
new CommandArgumentData<>(Boolean.class, BoolArgumentType::bool, BoolArgumentType::getBool),
new CommandArgumentData<>(String.class, StringArgumentType::string, StringArgumentType::getString)
);
/**
* Builds a command tree.
*/
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
{
LiteralArgumentBuilder<CommandSourceStack> builder = literal("config");
HashSet<String> addedCommands = new HashSet<>();
for (AbstractConfigBase<?> type : ConfigHandler.INSTANCE.configBaseList)
{
// Skip non-config entries
if (!(type instanceof ConfigEntry))
{
continue;
}
//noinspection PatternVariableCanBeUsed
ConfigEntry configEntry = (ConfigEntry) type;
if (configEntry.getChatCommandName() == null)
{
continue;
}
if (!addedCommands.add(configEntry.getChatCommandName()))
{
throw new IllegalStateException("Duplicate command name: " + configEntry.getChatCommandName());
}
LiteralArgumentBuilder<CommandSourceStack> subcommand = literal(configEntry.getChatCommandName())
.executes(commandContext -> this.sendSuccessResponse(commandContext,
"\n" +
"Description of §l" + configEntry.getChatCommandName() + "§r:\n" +
"§o" + configEntry.getComment().trim() + "§r\n" +
"§7Config file name: §f" + configEntry.name + "§7, category: §f" + configEntry.category + "\n" +
"\n" +
"Current value of " + configEntry.getChatCommandName() + " is §n" + configEntry.get() + "§r",
false
));
ToIntBiFunction<CommandContext<CommandSourceStack>, Object> updateConfigValue = (commandContext, value) -> {
configEntry.set(value);
return this.sendSuccessResponse(commandContext, "Changed the value of [" + configEntry.getChatCommandName() + "] to [" + value + "]", true);
};
// Enum type needs a special case since enums aren't represented by existing argument type
// and need literals for each individual value
if (Enum.class.isAssignableFrom(configEntry.getType()))
{
for (Object choice : configEntry.getType().getEnumConstants())
{
subcommand.then(
literal(choice.toString())
.executes(c -> updateConfigValue.applyAsInt(c, choice))
);
}
}
else
{
boolean setterAdded = false;
for (CommandArgumentData<?> commandArgumentData : commandArguments)
{
if (!commandArgumentData.argumentClass.isAssignableFrom(configEntry.getType()))
{
continue;
}
subcommand.then(argument("value", commandArgumentData.getArgumentType(configEntry))
.executes(c -> updateConfigValue.applyAsInt(c, commandArgumentData.getValue(c, "value"))));
setterAdded = true;
break;
}
if (!setterAdded)
{
throw new RuntimeException("Config type of " + type.getName() + " is not supported: " + configEntry.getType().getSimpleName());
}
}
builder.then(subcommand);
}
return builder;
}
private static class CommandArgumentData<T>
{
public final Class<T> argumentClass;
public final Function<ConfigEntry<T>, ArgumentType<T>> argumentTypeFunction;
private final BiFunction<CommandContext<CommandSourceStack>, String, T> valueGetter;
public CommandArgumentData(Class<T> argumentClass, Supplier<ArgumentType<T>> argumentTypeSupplier, BiFunction<CommandContext<CommandSourceStack>, String, T> valueGetter)
{
this(argumentClass, configEntry -> argumentTypeSupplier.get(), valueGetter);
}
public CommandArgumentData(Class<T> argumentClass, Function<ConfigEntry<T>, ArgumentType<T>> argumentTypeFunction, BiFunction<CommandContext<CommandSourceStack>, String, T> valueGetter)
{
this.argumentClass = argumentClass;
this.argumentTypeFunction = argumentTypeFunction;
this.valueGetter = valueGetter;
}
public ArgumentType<T> getArgumentType(ConfigEntry<T> configEntry)
{
return this.argumentTypeFunction.apply(configEntry);
}
public T getValue(CommandContext<CommandSourceStack> commandContext, String argumentName)
{
return this.valueGetter.apply(commandContext, argumentName);
}
}
#endif
}
@@ -1,90 +0,0 @@
package com.seibel.distanthorizons.common.commands;
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()
{
return literal("crash")
.requires(this::isPlayerSource)
.then(literal("encode")
.executes(c -> {
assert SharedApi.tryGetDhServerWorld() != null;
ServerPlayerState serverPlayerState = SharedApi.tryGetDhServerWorld().getServerPlayerStateManager()
.getConnectedPlayer(this.getSourcePlayer(c));
if (serverPlayerState != null)
{
serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.ENCODE));
}
return 1;
}))
.then(literal("decode")
.executes(c -> {
assert SharedApi.tryGetDhServerWorld() != null;
ServerPlayerState serverPlayerState = SharedApi.tryGetDhServerWorld().getServerPlayerStateManager()
.getConnectedPlayer(this.getSourcePlayer(c));
if (serverPlayerState != null)
{
serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.DECODE));
}
return 1;
}));
}
#endif
}
@@ -1,44 +0,0 @@
package com.seibel.distanthorizons.common.commands;
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;
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 -> {
return this.sendSuccessResponse(c, getDebugString(), false);
});
}
#else
public void execute(ICommandSender sender)
{
sender.sendMessage(new TextComponentString(getDebugString()));
}
#endif
}
@@ -1,218 +0,0 @@
package com.seibel.distanthorizons.common.commands;
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 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
{
private PregenManager getPregenManager()
{
DhServerWorld world = (DhServerWorld) Objects.requireNonNull(SharedApi.getAbstractDhWorld());
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()
{
LiteralArgumentBuilder<CommandSourceStack> statusCommand = literal("status")
.executes(this::pregenStatus);
LiteralArgumentBuilder<CommandSourceStack> startCommand = literal("start")
.then(argument("dimension", DimensionArgument.dimension())
.then(argument("origin", ColumnPosArgument.columnPos())
.then(argument("chunkRadius", integer(32))
.executes(this::pregenStart))));
LiteralArgumentBuilder<CommandSourceStack> stopCommand = literal("stop")
.executes(this::pregenStop);
return literal("pregen")
.then(statusCommand)
.then(startCommand)
.then(stopCommand);
}
private int pregenStatus(CommandContext<CommandSourceStack> c)
{
String statusString = this.getPregenManager().getStatusString();
//noinspection ReplaceNullCheck
if (statusString != null)
{
return this.sendSuccessResponse(c, statusString, false);
}
else
{
return this.sendSuccessResponse(c, "Pregen is not running", false);
}
}
private int pregenStart(CommandContext<CommandSourceStack> c) throws CommandSyntaxException
{
this.sendSuccessResponse(c, "Starting pregen. Progress will be in the server console.", true);
ServerLevel level = DimensionArgument.getDimension(c, "dimension");
ColumnPos origin = ColumnPosArgument.getColumnPos(c, "origin");
int chunkRadius = getInteger(c, "chunkRadius");
CompletableFuture<Void> future = this.getPregenManager().startPregen(
ServerLevelWrapper.getWrapper(level),
new DhBlockPos2D(#if MC_VER >= MC_1_19_2 origin.x(), origin.z() #else origin.x, origin.z #endif),
chunkRadius
);
future.whenComplete((result, throwable) -> {
if (throwable instanceof CancellationException)
{
this.sendSuccessResponse(c, "Pregen is cancelled", true);
return;
}
else if (throwable != null)
{
this.sendFailureResponse(c, "Pregen failed: " + throwable.getMessage() + "\n Check the logs for more details.");
return;
}
this.sendSuccessResponse(c, "Pregen is complete", true);
});
return 1;
}
private int pregenStop(CommandContext<CommandSourceStack> c)
{
CompletableFuture<Void> runningPregen = this.getPregenManager().getRunningPregen();
if (runningPregen == null)
{
return this.sendFailureResponse(c, "Pregen is not running");
}
runningPregen.cancel(true);
return 1;
}
#endif
}
@@ -1,101 +0,0 @@
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;
import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
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)
{
// always needs to be called, otherwise auto update setup won't be completed
boolean newUpdateAvailable = SelfUpdater.onStart();
if (!newUpdateAvailable)
{
return;
}
runnable = () ->
{
String versionId;
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
if (updateBranch == EDhApiUpdateBranch.STABLE)
{
versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
}
else
{
ArrayList<com.electronwill.nightconfig.core.Config> pipelines = GitlabGetter.INSTANCE.projectPipelines;
if (pipelines != null
&& pipelines.size() > 0)
{
versionId = pipelines.get(0).get("sha");
}
else
{
versionId = null;
}
}
if (versionId == null)
{
LOGGER.info("Unable to find new DH update for the ["+updateBranch+"] branch. Assuming DH is up to date...");
return;
}
// running on the render thread is required since setting the MC screen may trigger
// before its allowed, silently failing
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Update Screen", () ->
{
try
{
#if MC_VER <= MC_1_12_2
DhScreenUtil.setScreen(new UpdateModScreen(
new GuiMainMenu(),
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();
}
}
@@ -4,40 +4,17 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ServerApi; import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi; 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.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk;
#endif
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public class MixinChunkMapCommon 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) public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
#endif
{ {
IServerLevelWrapper levelWrapper = ServerLevelWrapper.getWrapper(level);
int chunkPosX;
int chunkPosZ;
#if MC_VER <= MC_1_21_11
chunkPosX = chunk.getPos().x;
chunkPosZ = chunk.getPos().z;
#else
chunkPosX = chunk.getPos().x();
chunkPosZ = chunk.getPos().z();
#endif
// is this position already being updated? // is this position already being updated?
if (SharedApi.isChunkAtChunkPosAlreadyUpdating(levelWrapper, chunkPosX, chunkPosZ)) if (SharedApi.isChunkAtChunkPosAlreadyUpdating(chunk.getPos().x, chunk.getPos().z))
{ {
return; return;
} }
@@ -45,31 +22,30 @@ public class MixinChunkMapCommon
// is this chunk being saved to disk? // is this chunk being saved to disk?
boolean savingChunkToDisk = #if MC_VER <= MC_1_12_2 true #else ci.getReturnValue() #endif; boolean savingChunkToDisk = ci.getReturnValue();
// true means a chunk was saved to disk // true means a chunk was saved to disk
if (!savingChunkToDisk) if (!savingChunkToDisk)
{ {
return; return;
} }
// TODO are the following validations necessary since we are checking above if
// the callback return value should state if the chunk was actually saved or not?
// Do we trust it to always be correct?
// corrupt/incomplete chunk validation // // corrupt/incomplete chunk validation //
// MC has a tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks) // 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 // this logic should prevent that from happening
#if MC_VER <= MC_1_12_2 #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
if (!chunk.isTerrainPopulated() || !chunk.isLightPopulated())
{
return;
}
#elif MC_VER <= MC_1_17_1
if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect()) if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
{ {
return; return;
} }
#else #else
if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect() || chunk instanceof ProtoChunk) if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect())
{ {
return; return;
} }
@@ -80,12 +56,7 @@ public class MixinChunkMapCommon
// biome validation // // biome validation //
// some chunks may be missing their biomes, which cause issues when attempting to save them // some chunks may be missing their biomes, which cause issues when attempting to save them
#if MC_VER <= MC_1_12_2 #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
if (chunk. getBiomeArray() == null)
{
return;
}
#elif MC_VER <= MC_1_17_1
if (chunk.getBiomes() == null) if (chunk.getBiomes() == null)
{ {
return; return;
@@ -106,8 +77,8 @@ public class MixinChunkMapCommon
// submit the update event // submit the update event
ServerApi.INSTANCE.serverChunkSaveEvent( ServerApi.INSTANCE.serverChunkSaveEvent(
new ChunkWrapper(chunk, levelWrapper), new ChunkWrapper(chunk, level, ServerLevelWrapper.getWrapper(level)),
levelWrapper ServerLevelWrapper.getWrapper(level)
); );
} }
@@ -1,62 +0,0 @@
package com.seibel.distanthorizons.common.commonMixins;
#if MC_VER > MC_1_12_2
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.modAccessor.AbstractImmersivePortalsAccessorCommon;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
import com.seibel.distanthorizons.core.util.math.DhVec3d;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.phys.Vec3;
public class MixinImmersivePortalsRenderStatesCommon
{
/**
* Used to access variables that will change when rendering
* different levels with Immersive Portals
* (ie player/camera position level reference)
* but that we only want for the loaded level.
*/
public static void saveVolatileOriginals()
{
Minecraft mc = Minecraft.getInstance();
AbstractImmersivePortalsAccessorCommon.actualLevel = mc.level;
// clear everything if the player is missing
// (ie the world hasn't loaded yet)
if (mc.player == null)
{
AbstractImmersivePortalsAccessorCommon.actualBlockPos = null;
AbstractImmersivePortalsAccessorCommon.actualChunkPos = null;
AbstractImmersivePortalsAccessorCommon.actualCameraPos = null;
return;
}
// player block pos
BlockPos playerBlockPos = mc.player.blockPosition();
AbstractImmersivePortalsAccessorCommon.actualBlockPos = new DhBlockPos(playerBlockPos.getX(), playerBlockPos.getY(), playerBlockPos.getZ());
// player chunk pos
#if MC_VER < MC_1_17_1
ChunkPos playerChunkPos = new ChunkPos(mc.player.blockPosition());
#else
ChunkPos playerChunkPos = mc.player.chunkPosition();
#endif
AbstractImmersivePortalsAccessorCommon.actualChunkPos = McObjectConverter.Convert(playerChunkPos);
// camera pos
#if MC_VER <= MC_1_21_10
Vec3 cameraPos = mc.gameRenderer.getMainCamera().getPosition();
#elif MC_VER <= MC_26_1_2
Vec3 cameraPos = mc.gameRenderer.getMainCamera().position();
#else
Vec3 cameraPos = mc.gameRenderer.mainCamera().position();
#endif
AbstractImmersivePortalsAccessorCommon.actualCameraPos = new DhVec3d(cameraPos.x(), cameraPos.y(), cameraPos.z());
}
}
#endif
@@ -1,153 +0,0 @@
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.modAccessor.IImmersivePortalsAccessor;
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.entity.Entity;
import net.minecraft.init.MobEffects;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fluids.IFluidBlock;
import net.minecraft.block.state.IBlockState;
#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;
import net.minecraft.client.renderer.fog.FogRenderer;
import net.minecraft.client.renderer.fog.FogData;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
#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();
// since DH won't render through immersive portals
// the vanilla fog should be enabled
IImmersivePortalsAccessor immersivePortals = ModAccessorInjector.INSTANCE.get(IImmersivePortalsAccessor.class);
if (immersivePortals != null
&& immersivePortals.isRenderingPortal())
{
cancelFog = false;
}
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
Entity view = mc.getRenderViewEntity();
if (view == null) return true;
IBlockState fluidState = mc.world.getBlockState(new BlockPos(view.getPositionEyes(mc.getRenderPartialTicks())));
boolean cameraNotInFluid = !(fluidState.getMaterial().isLiquid() || fluidState.getBlock() instanceof IFluidBlock);
#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;
}
}
@@ -1,312 +0,0 @@
/*
* 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.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDebugWireframeRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.pipeline.RenderPipeline;
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.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.DhMat4f;
import com.seibel.distanthorizons.core.util.math.DhVec3d;
import com.seibel.distanthorizons.core.util.math.DhVec3f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Handles rendering the wireframe particles
* that are used for seeing what the system's doing.
*/
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
// Pos x y z
0, 0, 0,
1, 0, 0,
1, 1, 0,
0, 1, 0,
0, 0, 1,
1, 0, 1,
1, 1, 1,
0, 1, 1,
//endregion
};
private static final int[] BOX_OUTLINE_INDICES = {
//region
0, 1,
1, 2,
2, 3,
3, 0,
4, 5,
5, 6,
6, 7,
7, 4,
0, 4,
1, 5,
2, 6,
3, 7,
//endregion
};
private static final DhMat4f TRANSFORM_MATRIX = new DhMat4f();
// rendering setup
private boolean init = false;
private RenderPipeline pipeline;
private GpuBuffer boxVertexBuffer;
private GpuBuffer boxIndexBuffer;
private final BlazeUniformBufferWrapper uniformBufferWrapper = new BlazeUniformBufferWrapper("debugWireframeUniformBlock");
//=============//
// constructor //
//=============//
//region
public BlazeDebugWireframeRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.createPipelines();
this.createBuffers();
}
private void createPipelines()
{
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(true);
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);
pipelineBuilder.withName("debug_wireframe_renderer");
pipelineBuilder.withVertexShader("debug/blaze/vert");
pipelineBuilder.withFragmentShader("debug/blaze/frag");
pipelineBuilder.withUniformBuffer("uniformBlock");
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
.build();
pipelineBuilder.withVertexFormat(vertexFormat);
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.LINES);
}
this.pipeline = pipelineBuilder.build();
}
private void createBuffers()
{
GpuDevice GPU_DEVICE = RenderSystem.getDevice();
CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
// box vertices
ByteBuffer boxVerticesBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES);
boxVerticesBuffer.order(ByteOrder.nativeOrder());
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
boxVerticesBuffer.rewind();
// upload vertex data
{
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int size = BOX_VERTICES.length * Float.BYTES;
this.boxVertexBuffer = GPU_DEVICE.createBuffer(() -> "distantHorizons:DebugWireframeBox", usage, size);
{
int length = BOX_VERTICES.length * Float.BYTES;
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.boxVertexBuffer, /*offset*/ 0, length);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES);
byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer.asFloatBuffer().put(BOX_VERTICES);
byteBuffer.rewind();
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
}
}
// box vertex indexes
{
ByteBuffer buffer = ByteBuffer.allocateDirect(BOX_OUTLINE_INDICES.length * Integer.BYTES);
buffer.order(ByteOrder.nativeOrder());
buffer.asIntBuffer().put(BOX_OUTLINE_INDICES);
buffer.rewind();
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX
| GpuBuffer.USAGE_INDEX
| GpuBuffer.USAGE_UNIFORM;
this.boxIndexBuffer = GPU_DEVICE.createBuffer(() -> "DH Debug Index Buffer", usage, buffer.capacity());
int offset = 0;
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.boxIndexBuffer, offset, buffer.capacity());
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
}
//endregion
//===========//
// rendering //
//===========//
//region
@Override
public void renderBox(Box box)
{
this.init();
//if (BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty()
// || BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty())
//{
// return;
//}
// shouldn't happen, but just in case
if (box == null)
{
return;
}
// delayed getters since this class may be initialized before
// the GPU device has been set
GpuDevice gpuDevice = RenderSystem.getDevice();
CommandEncoder commandEncoder = gpuDevice.createCommandEncoder();
// uniforms
{
// create data //
DhVec3d camPos = MC_RENDER.getCameraExactPosition();
DhVec3f camPosFloatThisFrame = new DhVec3f((float) camPos.x, (float) camPos.y, (float) camPos.z);
DhMat4f boxTransform = DhMat4f.createTranslateMatrix(
box.minPos.x - camPosFloatThisFrame.x,
box.minPos.y - camPosFloatThisFrame.y,
box.minPos.z - camPosFloatThisFrame.z);
boxTransform.multiply(DhMat4f.createScaleMatrix(
box.maxPos.x - box.minPos.x,
box.maxPos.y - box.minPos.y,
box.maxPos.z - box.minPos.z));
TRANSFORM_MATRIX.set(this.dhMvmProjMatrixThisFrame);
TRANSFORM_MATRIX.multiply(boxTransform);
// upload data //
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
.finishAndUpload()
;
}
// render //
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:DebugRenderer"; }
//endregion
}
#endif
@@ -1,613 +0,0 @@
/*
* 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.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDhGenericObjectRenderer {}
#else
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;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
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.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;
import com.seibel.distanthorizons.core.util.math.DhMat4f;
import com.seibel.distanthorizons.core.util.math.DhVec3d;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.ModInfo;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
/**
* Handles rendering generic groups of {@link DhApiRenderableBox}.
*
* @see IDhApiCustomRenderRegister
* @see DhApiRenderableBox
*/
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();
private static final DhApiRenderableBoxGroupShading DEFAULT_SHADING = DhApiRenderableBoxGroupShading.getUnshaded();
/**
* Can be used to troubleshoot the renderer.
* If enabled several debug objects will render around (0,150,0).
*/
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<>();
// rendering setup
private boolean init = false;
private RenderPipeline pipeline;
private final BlazeUniformBufferWrapper vertUniformBufferWrapper = new BlazeUniformBufferWrapper("vertUniformBlock");
//=============//
// constructor //
//=============//
//region
public BlazeDhGenericObjectRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.createPipelines();
if (RENDER_DEBUG_OBJECTS)
{
this.addGenericDebugObjects();
}
}
private void createPipelines()
{
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(true);
pipelineBuilder.withDepthWrite(true);
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);
pipelineBuilder.withName("generic_objects");
pipelineBuilder.withVertexShader("generic/blaze/vert");
pipelineBuilder.withFragmentShader("generic/blaze/frag");
pipelineBuilder.withSampler("uLightMap");
pipelineBuilder.withUniformBuffer("vertUniformBlock");
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
.add("aColor", BlazeDhVertexFormatUtil.RGBA_UBYTE_COLOR)
.add("aMaterial", BlazeDhVertexFormatUtil.IRIS_MATERIAL)
.add("paddingOne", BlazeDhVertexFormatUtil.BYTE_PAD)
.add("paddingTwo", BlazeDhVertexFormatUtil.BYTE_PAD)
.add("paddingThree", BlazeDhVertexFormatUtil.BYTE_PAD)
.build();
pipelineBuilder.withVertexFormat(vertexFormat);
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLES);
}
this.pipeline = pipelineBuilder.build();
}
private void addGenericDebugObjects()
{
GenericRenderObjectFactory factory = GenericRenderObjectFactory.INSTANCE;
// single giant box
IDhApiRenderableBoxGroup singleGiantBoxGroup = factory.createForSingleBox(
ModInfo.NAME + ":CyanChunkBox",
new DhApiRenderableBox(
new DhApiVec3d(0,0,0), new DhApiVec3d(16,190,16),
new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125),
EDhApiBlockMaterial.WATER)
);
singleGiantBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
singleGiantBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
this.add(singleGiantBoxGroup);
// single slender box
IDhApiRenderableBoxGroup singleTallBoxGroup = factory.createForSingleBox(
ModInfo.NAME + ":GreenBeacon",
new DhApiRenderableBox(
new DhApiVec3d(16,0,31), new DhApiVec3d(17,2000,32),
new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125),
EDhApiBlockMaterial.ILLUMINATED)
);
singleTallBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
singleTallBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
this.add(singleTallBoxGroup);
// absolute box group
ArrayList<DhApiRenderableBox> absBoxList = new ArrayList<>();
for (int i = 0; i < 18; i++)
{
absBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(i,150+i,24), new DhApiVec3d(1+i,151+i,25),
new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue()),
EDhApiBlockMaterial.LAVA
)
);
}
IDhApiRenderableBoxGroup absolutePosBoxGroup = factory.createAbsolutePositionedGroup(ModInfo.NAME + ":OrangeStairs", absBoxList);
this.add(absolutePosBoxGroup);
// relative box group
ArrayList<DhApiRenderableBox> relBoxList = new ArrayList<>();
for (int i = 0; i < 8; i+=2)
{
relBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(0,i,0), new DhApiVec3d(1,1+i,1),
new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue()),
EDhApiBlockMaterial.METAL
)
);
}
IDhApiRenderableBoxGroup relativePosBoxGroup = factory.createRelativePositionedGroup(
ModInfo.NAME + ":MovingMagentaGroup",
new DhApiVec3d(24, 140, 24),
relBoxList);
relativePosBoxGroup.setPreRenderFunc((event) ->
{
DhApiVec3d pos = relativePosBoxGroup.getOriginBlockPos();
pos.x += event.partialTicks / 2;
pos.x %= 32;
relativePosBoxGroup.setOriginBlockPos(pos);
});
this.add(relativePosBoxGroup);
// massive relative box group
ArrayList<DhApiRenderableBox> massRelBoxList = new ArrayList<>();
for (int x = 0; x < 50*2; x+=2)
{
for (int z = 0; z < 50*2; z+=2)
{
massRelBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(-x, 0, -z), new DhApiVec3d(1-x, 1, 1-z),
new Color(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue()),
EDhApiBlockMaterial.TERRACOTTA
)
);
}
}
IDhApiRenderableBoxGroup massRelativePosBoxGroup = factory.createRelativePositionedGroup(
ModInfo.NAME + ":MassRedGroup",
new DhApiVec3d(-25, 140, 0),
massRelBoxList);
massRelativePosBoxGroup.setPreRenderFunc((event) ->
{
DhApiVec3d blockPos = massRelativePosBoxGroup.getOriginBlockPos();
blockPos.y += event.partialTicks / 4;
if (blockPos.y > 150f)
{
blockPos.y = 140f;
Color newColor = (massRelativePosBoxGroup.get(0).color == Color.RED) ? Color.RED.darker() : Color.RED;
massRelativePosBoxGroup.forEach((box) -> { box.color = newColor; });
massRelativePosBoxGroup.triggerBoxChange();
}
massRelativePosBoxGroup.setOriginBlockPos(blockPos);
});
this.add(massRelativePosBoxGroup);
}
//endregion
//==============//
// registration //
//==============//
//region
@Override
public void add(IDhApiRenderableBoxGroup iBoxGroup) throws IllegalArgumentException
{
if (!(iBoxGroup instanceof RenderableBoxGroup))
{
throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"], type received: ["+(iBoxGroup != null ? iBoxGroup.getClass() : "NULL")+"].");
}
RenderableBoxGroup boxGroup = (RenderableBoxGroup) iBoxGroup;
if (boxGroup.size() != 0)
{
// trigger a box change to make sure the initial data is uploaded
boxGroup.triggerBoxChange();
}
long id = boxGroup.getId();
if (this.boxGroupById.containsKey(id))
{
throw new IllegalArgumentException("A box group with the ID [" + id + "] is already present.");
}
this.boxGroupById.put(id, boxGroup);
}
@Override
public IDhApiRenderableBoxGroup remove(long id) { return this.boxGroupById.remove(id); }
public void clear() { this.boxGroupById.clear(); }
//endregion
//===========//
// rendering //
//===========//
//region
/**
* @param renderingWithSsao
* if true that means this render call is happening before the SSAO pass
* and any objects rendered in this pass will have SSAO applied to them.
*/
@Override
public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao)
{
try (IProfilerWrapper.IProfileBlock generic_profile = profiler.push("setup"))
{
//==============//
// render setup //
//==============//
//#region
this.init();
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam.apiCopy);
DhVec3d camPos = MC_RENDER.getCameraExactPosition();
//#endregion
if (BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty())
{
return;
}
//===========//
// rendering //
//===========//
//#region
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
for (RenderableBoxGroup boxGroup : boxList)
{
// validation //
// shouldn't happen, but just in case
if (boxGroup == null)
{
continue;
}
// skip boxes that shouldn't render this pass
if (boxGroup.ssaoEnabled != renderingWithSsao)
{
continue;
}
profiler.popPush("render prep");
boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired
// ignore inactive groups
if (!boxGroup.active)
{
continue;
}
// allow API users to cancel this object's rendering
EVENT_PARAM.update(renderEventParam, boxGroup);
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, EVENT_PARAM);
if (cancelRendering)
{
continue;
}
// update instanced data if needed
{
boxGroup.tryUpdateInstancedDataAsync();
// skip groups that haven't been uploaded yet
if (boxGroup.vertexBufferContainer.getState() != IDhGenericObjectVertexBufferContainer.EState.RENDER)
{
continue;
}
}
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
if (shading == null)
{
shading = DEFAULT_SHADING;
}
// uniforms
{
// create data //
DhMat4f projectionMvmMatrix = new DhMat4f(renderEventParam.dhProjectionMatrix);
projectionMvmMatrix.multiply(renderEventParam.dhModelViewMatrix);
// upload data //
this.vertUniformBufferWrapper
.putVec3i(
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
) // uOffsetChunk
.putVec3f(
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
) // uOffsetSubChunk
.putVec3i(
LodUtil.getChunkPosFromDouble(camPos.x),
LodUtil.getChunkPosFromDouble(camPos.y),
LodUtil.getChunkPosFromDouble(camPos.z)
) // uCameraPosChunk
.putVec3f(
LodUtil.getSubChunkPosFromDouble(camPos.x),
LodUtil.getSubChunkPosFromDouble(camPos.y),
LodUtil.getSubChunkPosFromDouble(camPos.z)
) // uCameraPosSubChunk
.putMat4f(projectionMvmMatrix) // uProjectionMvm
.putInt(boxGroup.getSkyLight()) // uSkyLight
.putInt(boxGroup.getBlockLight()) // uBlockLight
.putFloat(shading.north)
.putFloat(shading.south)
.putFloat(shading.east)
.putFloat(shading.west)
.putFloat(shading.top)
.putFloat(shading.bottom)
.finishAndUpload()
;
}
// render //
profiler.popPush("rendering");
try (IProfilerWrapper.IProfileBlock namespace_profile = profiler.push(boxGroup.getResourceLocationNamespace());
IProfilerWrapper.IProfileBlock location_profile = profiler.push(boxGroup.getResourceLocationPath()))
{
this.renderBoxGroupInstanced(renderEventParam, boxGroup, profiler);
}
boxGroup.postRender(renderEventParam);
}
//#endregion
//==========//
// clean up //
//==========//
//region
profiler.popPush("cleanup");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
//endregion
}
}
private String getRenderPassName() { return "distantHorizons:GenericObjectRenderer"; }
//endregion
//=====================//
// instanced rendering //
//=====================//
//region
private void renderBoxGroupInstanced(
RenderParams renderEventParam,
RenderableBoxGroup boxGroup,
IProfilerWrapper profiler)
{
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper,
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper))
{
// update instance data //
BlazeGenericObjectVertexContainer container = (BlazeGenericObjectVertexContainer) boxGroup.vertexBufferContainer;
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
renderPassWrapper.bindTexture("uLightMap", lightmapTextureViewWrapper);
// Bind instance data //
renderPassWrapper.setUniform("vertUniformBlock", this.vertUniformBufferWrapper);
// set pipeline
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.setIndexBuffer(container.indexGpuBuffer);
renderPassWrapper.setVertexBuffer(container.vboGpuBuffer);
// Draw instanced
if (container.uploadedBoxCount > 0)
{
// 36 = 6 faces * 6 verticies per face
renderPassWrapper.drawIndexed(container.uploadedBoxCount * 36);
}
}
}
//endregion
//=========//
// F3 menu //
//=========//
//region
public String getVboRenderDebugMenuString()
{
// get counts
int totalGroupCount = this.boxGroupById.size();
int totalBoxCount = 0;
int activeGroupCount = 0;
int activeBoxCount = 0;
for (long key : this.boxGroupById.keySet())
{
RenderableBoxGroup renderGroup = this.boxGroupById.get(key);
if (renderGroup.active)
{
activeGroupCount++;
activeBoxCount += renderGroup.size();
}
totalBoxCount += renderGroup.size();
}
return "Generic Obj #: " + F3Screen.NUMBER_FORMAT.format(activeGroupCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalGroupCount) + ", " +
"Cube #: " + F3Screen.NUMBER_FORMAT.format(activeBoxCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalBoxCount);
}
//endregion
//================//
// 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
@@ -1,122 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDhMetaRenderer {}
#else
import com.mojang.blaze3d.textures.GpuTexture;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterColorDepthTextureCreatedEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiTextureCreatedParam;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
import com.seibel.distanthorizons.common.render.blaze.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;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import net.minecraft.client.Minecraft;
import java.awt.*;
public class BlazeDhMetaRenderer implements IDhMetaRenderer
{
public static final BlazeDhMetaRenderer INSTANCE = new BlazeDhMetaRenderer();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private BlazeDhApplyRenderer applyRenderer;
private final float clearDepth;
public final BlazeTextureWrapper dhDepthTextureWrapper = BlazeTextureWrapper.createDepth("DhDepthTexture");
public final BlazeTextureWrapper dhColorTextureWrapper = BlazeTextureWrapper.createColor("DhColorTexture");
//=============//
// constructor //
//=============//
//region
private BlazeDhMetaRenderer()
{
AbstractDhRenderApiDefinition renderApiDefinition = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
this.clearDepth = renderApiDefinition.getRenderDepth().farDepth;
this.applyRenderer = new BlazeDhApplyRenderer(
"dh_apply_to_mc",
null,
"apply/blaze/vert", "apply/blaze/frag"
);
}
//endregion
//=================//
// pre/post render //
//=================//
//region
@Override
public void runRenderPassSetup(RenderParams renderParams)
{
int oldWidth = this.dhDepthTextureWrapper.getWidth();
int oldHeight = this.dhDepthTextureWrapper.getHeight();
boolean texturesChanged = false;
texturesChanged = this.dhDepthTextureWrapper.tryCreateOrResize() | texturesChanged;
texturesChanged = this.dhColorTextureWrapper.tryCreateOrResize() | texturesChanged;
if (texturesChanged)
{
int newTextureWidth = MC_RENDER.getTargetFramebufferViewportWidth();
int newTextureHeight = MC_RENDER.getTargetFramebufferViewportHeight();
DhApiTextureCreatedParam textureCreatedParam = new DhApiTextureCreatedParam(
oldWidth, oldHeight,
newTextureWidth, newTextureHeight
);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterColorDepthTextureCreatedEvent.class, textureCreatedParam);
}
}
@Override
public void runRenderPassCleanup(RenderParams renderParams) {}
@Override
public void applyToMcTexture(RenderParams renderParams)
{
GpuTexture mcColorTexture = MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture();
this.applyRenderer.render(this.dhColorTextureWrapper.texture, this.dhDepthTextureWrapper.texture, mcColorTexture);
}
//endregion
//================//
// clear textures //
//================//
//region
@Override
public void clearDhDepthAndColorTextures(RenderParams renderParams)
{
this.dhDepthTextureWrapper.clearDepth(this.clearDepth);
Color color = MC_RENDER.getSkyColor();
this.dhColorTextureWrapper.clearColor(ColorUtil.toColorInt(color));
}
//endregion
}
#endif
@@ -1,114 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDhRenderApiDefinition {}
#else
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
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;
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeDhSsaoRenderer;
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeVanillaFadeRenderer;
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;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
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
{
//=========//
// getters //
//=========//
//region
private final String engineName;
public String getEngineName() { return this.engineName; }
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
// Blaze always uses the same rendering API as Minecraft
this.renderApi = MinecraftRenderWrapper.INSTANCE.getMcRenderingApi();
#endif
this.engineName = "Blaze3D: " + this.getRenderApi();
}
//endregion
//============//
// singletons //
//============//
//region
@Override public IDhMetaRenderer getMetaRenderer() { return BlazeDhMetaRenderer.INSTANCE; }
@Override public IDhTerrainRenderer getTerrainRenderer() { return BlazeDhTerrainRenderer.INSTANCE; }
@Override public IDhSsaoRenderer getSsaoRenderer() { return BlazeDhSsaoRenderer.INSTANCE; }
@Override public IDhFogRenderer getFogRenderer() { return BlazeDhFogRenderer.INSTANCE; }
@Override public IDhFarFadeRenderer getFarFadeRenderer() { return BlazeDhFarFadeRenderer.INSTANCE; }
@Override public AbstractDebugWireframeRenderer getDebugWireframeRenderer() { return BlazeDebugWireframeRenderer.INSTANCE; }
@Override public IDhVanillaFadeRenderer getVanillaFadeRenderer() { return BlazeVanillaFadeRenderer.INSTANCE; }
@Override public IDhTestTriangleRenderer getTestTriangleRenderer() { return BlazeDhTestTriangleRenderer.INSTANCE; }
//endregion
//===========//
// factories //
//===========//
//region
@Override public IDhGenericRenderer createGenericRenderer() { return new BlazeDhGenericObjectRenderer(); }
@Override public IVertexBufferWrapper createVboWrapper(String name) { return new BlazeVertexBufferWrapper(name); }
@Override public ILodContainerUniformBufferWrapper createLodContainerUniformWrapper() { return new BlazeLodUniformBufferWrapper(); }
@Override public IDhGenericObjectVertexBufferContainer createGenericVboContainer() { return new BlazeGenericObjectVertexContainer(); }
//endregion
}
#endif
@@ -1,338 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDhTerrainRenderer {}
#else
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;
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.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.DhMat4f;
import com.seibel.distanthorizons.core.util.math.DhVec3d;
import com.seibel.distanthorizons.core.util.math.DhVec3f;
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;
/** 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 DhVec3f MODEL_POS = new DhVec3f();
/** 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 final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("fragUniformBlock");
private final BlazeUniformBufferWrapper vertSharedUniformBufferWrapper = new BlazeUniformBufferWrapper("vertSharedUniformBlock");
//=============//
// constructor //
//=============//
//region
private BlazeDhTerrainRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
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);
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.withSampler("uLightMap");
pipelineBuilder.withVertexShader("lod/blaze/vert");
pipelineBuilder.withFragmentShader("lod/blaze/frag");
pipelineBuilder.withUniformBuffer("vertUniqueUniformBlock");
pipelineBuilder.withUniformBuffer("vertSharedUniformBlock");
pipelineBuilder.withUniformBuffer("fragUniformBlock");
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
.add("vPosition", BlazeDhVertexFormatUtil.SHORT_XYZ_POS)
.add("meta", BlazeDhVertexFormatUtil.META)
.add("vColor", BlazeDhVertexFormatUtil.RGBA_UBYTE_COLOR)
.add("irisMaterial", BlazeDhVertexFormatUtil.IRIS_MATERIAL)
.add("irisNormal", BlazeDhVertexFormatUtil.IRIS_NORMAL)
.add("paddingTwo", BlazeDhVertexFormatUtil.BYTE_PAD)
.add("paddingThree", BlazeDhVertexFormatUtil.BYTE_PAD) // padding is to make sure the format is a multiple of 4
.build();
pipelineBuilder.withVertexFormat(vertexFormat);
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLES);
}
// opaque
{
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);
translucentPipelineBuilder.withBlend(BlendFunction.TRANSLUCENT);
this.transparentPipeline = translucentPipelineBuilder.build();
}
this.init = true;
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(
RenderParams renderEventParam,
boolean opaquePass,
SortedArraySet<LodBufferContainer> bufferContainers,
IProfilerWrapper profiler)
{
this.tryInit();
try(IProfilerWrapper.IProfileBlock terrain_profile = profiler.push("terrain render"))
{
profiler.popPush("vert unique uniforms");
{
// create data //
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
bufferContainer.uniformContainer.tryUpload(bufferContainer);
}
}
profiler.popPush("vert share uniforms");
{
DhMat4f combinedMatrix = new DhMat4f(renderEventParam.dhProjectionMatrix);
combinedMatrix.multiply(renderEventParam.dhModelViewMatrix);
float earthCurveRatio = Config.Client.Advanced.Graphics.Experimental.earthCurveRatio.get();
if (earthCurveRatio < -1.0f || earthCurveRatio > 1.0f)
{
earthCurveRatio = /*6371KM*/ 6371000.0f / earthCurveRatio;
}
else
{
// disable curvature if the config value is between -1 and 1
earthCurveRatio = 0.0f;
}
// upload data //
int i = Config.Client.Advanced.Debugging.enableWhiteWorld.get() ? 1 : 0;
this.vertSharedUniformBufferWrapper
.putInt(i) // uIsWhiteWorld
.putFloat((float) renderEventParam.worldYOffset) // uWorldYOffset
.putFloat(0.01f) // uMircoOffset // 0.01 block offset
.putFloat(earthCurveRatio) // uEarthRadius
.putVec3f(
(float) renderEventParam.exactCameraPosition.x,
(float) renderEventParam.exactCameraPosition.y,
(float) renderEventParam.exactCameraPosition.z) // uCameraPos
.putMat4f(combinedMatrix) // uCombinedMatrix
.finishAndUpload();
}
profiler.popPush("set frag uniforms");
{
// create data //
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
if (!Config.Client.Advanced.Debugging.lodOnlyMode.get())
{
// this added value prevents the near clip plane and discard circle from touching, which looks bad
dhNearClipDistance += 16f;
}
// upload data //
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
.finishAndUpload()
;
}
// render pass setup
{
profiler.popPush("rendering");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam.apiCopy);
// create a render pass
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper,
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper)
)
{
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
renderPassWrapper.bindTexture("uLightMap", lightmapTextureViewWrapper);
// set pipeline
renderPassWrapper.setPipeline(opaquePass ? this.opaquePipeline : this.transparentPipeline);
// shared uniforms
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
renderPassWrapper.setUniform("vertSharedUniformBlock", this.vertSharedUniformBufferWrapper);
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
BlazeLodUniformBufferWrapper uniformWrapper = (BlazeLodUniformBufferWrapper) bufferContainer.uniformContainer;
boolean columnBuilderDebugEnabled = Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugEnable.get();
if (columnBuilderDebugEnabled)
{
if (DhSectionPos.getDetailLevel(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugDetailLevel.get()
&& DhSectionPos.getX(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugXPos.get()
&& DhSectionPos.getZ(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugZPos.get())
{
int breakpoint = 0;
}
else
{
continue;
}
}
renderPassWrapper.setUniform("vertUniqueUniformBlock", uniformWrapper);
// render each buffer
IVertexBufferWrapper[] bufferWrapperList = opaquePass ? bufferContainer.vboOpaqueWrappers : bufferContainer.vboTransparentWrappers;
for (int i = 0; i < bufferWrapperList.length; i++)
{
BlazeVertexBufferWrapper bufferWrapper = (BlazeVertexBufferWrapper) bufferWrapperList[i];
if (!bufferWrapper.uploaded
|| bufferWrapper.vertexCount == 0)
{
continue;
}
// fire render event
{
DhVec3d camPos = renderEventParam.exactCameraPosition;
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);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, BEFORE_BUFFER_RENDER_EVENT_PARAM);
}
renderPassWrapper.setIndexBuffer(bufferWrapper.getIndexGpuBuffer());
renderPassWrapper.setVertexBuffer(bufferWrapper.vertexGpuBuffer);
if (!bufferWrapper.vertexGpuBuffer.isClosed())
{
renderPassWrapper.drawIndexed(bufferWrapper.indexCount);
}
}
}
}
}
}
}
private String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
private String getRenderPassName() { return "distantHorizons:TerrainRenderer"; }
//endregion
}
#endif
@@ -1,284 +0,0 @@
/*
* 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.common.render.blaze.apply;
#if MC_VER <= MC_1_21_10
public class BlazeDhApplyRenderer {}
#else
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;
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;
/**
* Copies the given color texture
* where the depth (or another attribute) is valid.
* Often used to apply post processing effects or
* the DH texture to MC's color texture. <br><br>
*
* @see BlazeDhCopyRenderer
*/
public class BlazeDhApplyRenderer
{
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;
protected final String identifierName;
public String getIdentifierName() { return this.identifierName; }
@Nullable
private final BlendFunction blendFunction;
private final String vertexShaderPath;
private final String fragmentShaderPath;
private final BlazeTextureViewWrapper sourceColorTextureViewWrapper = new BlazeTextureViewWrapper();
private final BlazeTextureViewWrapper sourceDepthTextureViewWrapper = new BlazeTextureViewWrapper();
private final BlazeTextureViewWrapper destinationColorTextureViewWrapper = new BlazeTextureViewWrapper();
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
private final BlazeTextureWrapper dummyDepthTextureWrapper = BlazeTextureWrapper.createDepth("apply_dummy_depth");
/**
* Can be set for special application shaders that need
* extra information. <br><br>
*
* will be an empty array if unneeded
*/
private final String[] uniformNames;
/** will be an empty array if unneeded */
private final BlazeUniformBufferWrapper[] uniformBufferWrappers;
//=============//
// constructor //
//=============//
//region
public BlazeDhApplyRenderer(
String name,
@Nullable BlendFunction blendFunction,
String vertexShaderPath, String fragmentShaderPath
)
{
this(
name,
blendFunction,
vertexShaderPath, fragmentShaderPath,
new String[0] // no extra uniforms
);
}
public BlazeDhApplyRenderer(
String name,
@Nullable BlendFunction blendFunction,
String vertexShaderPath, String fragmentShaderPath,
String[] uniformNames
)
{
this.name = name;
this.identifierName = "distanthorizons:"+this.name;
this.blendFunction = blendFunction;
this.vertexShaderPath = vertexShaderPath;
this.fragmentShaderPath = fragmentShaderPath;
this.uniformNames = uniformNames;
this.uniformBufferWrappers = new BlazeUniformBufferWrapper[this.uniformNames.length];
}
private void tryInit(
GpuTexture sourceColorTexture,
GpuTexture sourceDepthTexture,
GpuTexture destinationColorTexture)
{
// one-time setup
if (this.pipeline == null)
{
this.createPipeline();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData(this.name);
}
this.sourceColorTextureViewWrapper.tryWrap(sourceColorTexture);
this.sourceDepthTextureViewWrapper.tryWrap(sourceDepthTexture);
this.destinationColorTextureViewWrapper.tryWrap(destinationColorTexture);
}
private void createPipeline()
{
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
if (this.blendFunction != null)
{
pipelineBuilder.withBlend(this.blendFunction);
}
else
{
pipelineBuilder.withoutBlend();
}
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName(this.name);
pipelineBuilder.withVertexShader(this.vertexShaderPath);
pipelineBuilder.withFragmentShader(this.fragmentShaderPath);
for (int i = 0; i < this.uniformNames.length; i++)
{
String uniformName = this.uniformNames[i];
pipelineBuilder.withUniformBuffer(uniformName);
}
pipelineBuilder.withUniformBuffer("baseFragUniformBlock");
pipelineBuilder.withSampler("uSourceColorTexture");
pipelineBuilder.withSampler("uSourceDepthTexture");
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
.build();
pipelineBuilder.withVertexFormat(vertexFormat);
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
}
//endregion
//========//
// render //
//========//
//region
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
for (int i = 0; i < this.uniformNames.length; i++)
{
String nameAtIndex = this.uniformNames[i];
if (nameAtIndex.equals(uniformName))
{
this.uniformBufferWrappers[i] = uniformBufferWrapper;
break;
}
}
}
public void render(
GpuTexture sourceColorTexture,
GpuTexture sourceDepthTexture,
GpuTexture destinationColorTexture)
{
this.tryInit(sourceColorTexture, sourceDepthTexture, destinationColorTexture);
this.dummyDepthTextureWrapper.tryCreateOrResize();
this.fragUniformBufferWrapper
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
.finishAndUpload();
;
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getIdentifierName,
this.destinationColorTextureViewWrapper,
this.dummyDepthTextureWrapper))
{
renderPassWrapper.bindTexture("uSourceColorTexture", this.sourceColorTextureViewWrapper);
renderPassWrapper.bindTexture("uSourceDepthTexture", this.sourceDepthTextureViewWrapper);
for (int i = 0; i < this.uniformNames.length; i++)
{
String uniformName = this.uniformNames[i];
BlazeUniformBufferWrapper uniformBuffer = this.uniformBufferWrappers[i];
if (uniformBuffer == null)
{
throw new IllegalStateException("Missing uniform ["+uniformName+"], please set the uniform before rendering.");
}
renderPassWrapper.setUniform(uniformName, uniformBuffer);
}
renderPassWrapper.setUniform("baseFragUniformBlock", this.fragUniformBufferWrapper);
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.draw(4);
}
// clear the uniforms after rendering
// so we can check if they're missing during next frame's rendering
if (ModInfo.IS_DEV_BUILD)
{
Arrays.fill(this.uniformBufferWrappers, null);
}
}
//endregion
}
#endif
@@ -1,145 +0,0 @@
/*
* 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.common.render.blaze.apply;
#if MC_VER <= MC_1_21_10
public class BlazeDhCopyRenderer {}
#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.RenderSystem;
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;
/**
* Blindly copies one texture into another.
*
* @see BlazeDhApplyRenderer
*/
public class BlazeDhCopyRenderer
{
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();
public static final BlazeDhCopyRenderer INSTANCE = new BlazeDhCopyRenderer();
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer vboGpuBuffer;
private BlazeTextureWrapper dummyDepthTextureWrapper;
//=============//
// constructor //
//=============//
//region
private BlazeDhCopyRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
this.dummyDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_copy_depth_texture");
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("copy");
pipelineBuilder.withVertexShader("copy/blaze/vert");
pipelineBuilder.withFragmentShader("copy/blaze/frag");
pipelineBuilder.withSampler("uCopyTexture");
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("CopyRenderer");
}
//endregion
//========//
// render //
//========//
//region
public void render(
IDhBlazeTexture sourceColorTextureWrapper,
IDhBlazeTexture destinationColorTextureWrapper)
{
this.tryInit();
this.dummyDepthTextureWrapper.tryCreateOrResize();
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
destinationColorTextureWrapper,
this.dummyDepthTextureWrapper))
{
renderPassWrapper.bindTexture("uCopyTexture", sourceColorTextureWrapper);
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.draw(4);
}
}
private String getRenderPassName() { return "distantHorizons:CopyRenderer"; }
//endregion
}
#endif
@@ -1,299 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.objects;
#if MC_VER <= MC_1_21_10
public class BlazeGenericObjectVertexContainer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
/**
* For use by {@link RenderableBoxGroup}
*
* @see RenderableBoxGroup
*/
public class BlazeGenericObjectVertexContainer implements IDhGenericObjectVertexBufferContainer
{
private 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 static final int[] BOX_INDICES = {
//region
// min X, vertical face
2, 1, 0,
0, 3, 2,
// max X, vertical face
6, 5, 4,
4, 7, 6,
// min Z, vertical face
10, 9, 8,
8, 11, 10,
// max Z, vertical face
14, 13, 12,
12, 15, 14,
// min Y, horizontal face
18, 17, 16,
16, 19, 18,
// max Y, horizontal face
20, 21, 22,
22, 23, 20,
//endregion
};
public GpuBuffer vboGpuBuffer;
public GpuBuffer indexGpuBuffer;
private ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(0);
private ByteBuffer indexBuffer = ByteBuffer.allocateDirect(0);
public int uploadedBoxCount = 0;
private EState state = EState.NEW;
@Override
public IDhGenericObjectVertexBufferContainer.EState getState() { return this.state; }
@Override
public void setState(IDhGenericObjectVertexBufferContainer.EState state) { this.state = state; }
//===========================//
// render building/uploading //
//===========================//
//region
@Override
public void updateVertexData(List<DhApiRenderableBox> uploadBoxList)
{
int boxCount = uploadBoxList.size();
// recreate the data arrays if their size is different
if (this.uploadedBoxCount != boxCount)
{
this.uploadedBoxCount = boxCount;
int vertexBufferSize = this.vertexBufferSize();
this.vertexBuffer = ByteBuffer.allocateDirect(vertexBufferSize);
this.vertexBuffer.order(ByteOrder.nativeOrder());
int indexBufferSize = this.indexBufferSize();
this.indexBuffer = ByteBuffer.allocateDirect(indexBufferSize);
this.indexBuffer.order(ByteOrder.nativeOrder());
}
this.vertexBuffer.position(0);
this.indexBuffer.position(0);
for (int boxIndex = 0; boxIndex < boxCount; boxIndex++)
{
// index
int indexOffset = (boxIndex * 24 /*24 is the number of vertices in a box*/);
for (int i = 0; i < BOX_INDICES.length; i++)
{
this.indexBuffer.putInt(BOX_INDICES[i] + indexOffset);
}
// vertex
DhApiRenderableBox box = uploadBoxList.get(boxIndex);
final double[] boxVertices =
{
//region
// Pos x y z
// min X, vertical face
box.minPos.x, box.minPos.y, box.minPos.z,
box.maxPos.x, box.minPos.y, box.minPos.z,
box.maxPos.x, box.maxPos.y, box.minPos.z,
box.minPos.x, box.maxPos.y, box.minPos.z,
// max X, vertical face
box.minPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.minPos.y, box.maxPos.z,
box.minPos.x, box.minPos.y, box.maxPos.z,
// min Z, vertical face
box.minPos.x, box.minPos.y, box.maxPos.z,
box.minPos.x, box.minPos.y, box.minPos.z,
box.minPos.x, box.maxPos.y, box.minPos.z,
box.minPos.x, box.maxPos.y, box.maxPos.z,
// max Z, vertical face
box.maxPos.x, box.minPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.minPos.z,
box.maxPos.x, box.minPos.y, box.minPos.z,
// min Y, horizontal face
box.minPos.x, box.minPos.y, box.maxPos.z,
box.maxPos.x, box.minPos.y, box.maxPos.z,
box.maxPos.x, box.minPos.y, box.minPos.z,
box.minPos.x, box.minPos.y, box.minPos.z,
// max Y, horizontal face
box.minPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.minPos.z,
box.minPos.x, box.maxPos.y, box.minPos.z,
//endregion
};
for (int vertexIndex = 0; vertexIndex < boxVertices.length; vertexIndex+=3)
{
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex]); // x
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex+1]); // y
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex+2]); // z
int color = ColorUtil.toColorInt(box.color);
byte r = (byte) ColorUtil.getRed(color);
byte g = (byte) ColorUtil.getGreen(color);
byte b = (byte) ColorUtil.getBlue(color);
byte a = (byte) ColorUtil.getAlpha(color);
this.vertexBuffer.put(r);
this.vertexBuffer.put(g);
this.vertexBuffer.put(b);
this.vertexBuffer.put(a);
this.vertexBuffer.put(box.material);
// padding so the vertex format's byte count is a multiple of 4
this.vertexBuffer.put((byte)0);
this.vertexBuffer.put((byte)0);
this.vertexBuffer.put((byte)0);
}
}
this.vertexBuffer.flip();
this.indexBuffer.flip();
}
private int vertexBufferSize()
{
// minimum of 1 box to prevent trying to create a buffer of size 0
int boxCount = Math.max(this.uploadedBoxCount, 1);
int faceCount = boxCount * 6; // 6 faces on a cube
int vertexCount = faceCount * 6; // 6 vertices per cube
int byteSize = vertexCount * 3 * Float.BYTES; // x,y,z
byteSize += vertexCount * 4; // r,g,b,a
byteSize += 1; // material
return byteSize;
}
private int indexBufferSize()
{
// minimum of 1 box to prevent trying to create a buffer of size 0
int boxCount = Math.max(this.uploadedBoxCount, 1);
int quadCount = boxCount * 6 * 6; // 6 faces with 6 vertices each
int byteSize = quadCount * GLEnums.getTypeSize(GL32.GL_UNSIGNED_INT);
return byteSize;
}
@Override
public void uploadDataToGpu()
{
// vertex
{
int totalVertexByteSize = this.vertexBufferSize();
if (this.vboGpuBuffer == null
// recreating if the size changes is always necessary (even if we only need a smaller amount)
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|| this.vboGpuBuffer.size() != totalVertexByteSize)
{
if (this.vboGpuBuffer != null)
{
this.vboGpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getVertexBufferName, usage, totalVertexByteSize);
}
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, /*offset*/0, totalVertexByteSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.vertexBuffer);
}
// index
{
int totalVertexByteSize = this.indexBufferSize();
if (this.indexGpuBuffer == null
// recreating if the size changes is always necessary (even if we only need a smaller amount)
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|| this.indexGpuBuffer.size() != totalVertexByteSize)
{
if (this.indexGpuBuffer != null)
{
this.indexGpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_INDEX;
this.indexGpuBuffer = GPU_DEVICE.createBuffer(this::getIndexBufferName, usage, totalVertexByteSize);
}
int offset = 0;
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, offset, totalVertexByteSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.indexBuffer);
}
}
private String getVertexBufferName() { return "distantHorizons:GenericVertexBuffer"; }
private String getIndexBufferName() { return "distantHorizons:GenericIndexBuffer"; }
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("BlazeGenericObjectVertexContainer close", () ->
{
if (this.vboGpuBuffer != null)
{
this.vboGpuBuffer.close();
}
if (this.indexGpuBuffer != null)
{
this.indexGpuBuffer.close();
}
});
}
//endregion
}
#endif
@@ -1,207 +0,0 @@
/*
* 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.common.render.blaze.postProcessing;
#if MC_VER <= MC_1_21_10
public class BlazeDhFarFadeRenderer {}
#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.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.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.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFarFadeRenderer;
/**
* Fades out DH's far clip plane
*/
public class BlazeDhFarFadeRenderer implements IDhFarFadeRenderer
{
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 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 final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("fragUniformBlock");
private GpuBuffer vboGpuBuffer;
private final BlazeTextureWrapper dhFadeColorTextureWrapper = BlazeTextureWrapper.createColor("dh_far_fade_color_texture");
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
private final BlazeTextureWrapper dhFadeDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_far_fade_depth_texture");
private final BlazeTextureViewWrapper mcColorTextureViewWrapper = new BlazeTextureViewWrapper();
//=============//
// constructor //
//=============//
//region
private BlazeDhFarFadeRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("far_fade");
pipelineBuilder.withVertexShader("fade/blaze/vert");
pipelineBuilder.withFragmentShader("fade/blaze/dh_fade");
pipelineBuilder.withSampler("uMcColorTexture");
pipelineBuilder.withSampler("uDhDepthTexture");
pipelineBuilder.withSampler("uDhColorTexture");
pipelineBuilder.withUniformBuffer("fragUniformBlock");
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("DhFarFadeRenderer");
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
{
return;
}
// textures
this.dhFadeColorTextureWrapper.tryCreateOrResize();
this.mcColorTextureViewWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture());
this.dhFadeDepthTextureWrapper.tryCreateOrResize();
{
// create data //
float dhFarClipDistance = RenderUtil.getFarClipPlaneDistanceInBlocks();
float fadeStartDistance = dhFarClipDistance * 0.5f;
float fadeEndDistance = dhFarClipDistance * 0.9f;
// upload data //
fragUniformBufferWrapper
.putFloat(fadeStartDistance) // uStartFadeBlockDistance
.putFloat(fadeEndDistance) // uEndFadeBlockDistance
.putMat4f(renderParams.dhInverseMvmProjectionMatrix) // uDhInvMvmProj
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
.finishAndUpload()
;
}
this.renderFadeToTexture();
BlazeDhCopyRenderer.INSTANCE.render(this.dhFadeColorTextureWrapper, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper);
}
private void renderFadeToTexture()
{
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
this.dhFadeColorTextureWrapper,
this.dhFadeDepthTextureWrapper))
{
// MC texture
renderPassWrapper.bindTexture("uMcColorTexture", this.mcColorTextureViewWrapper);
// DH textures
renderPassWrapper.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper);
renderPassWrapper.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper);
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.draw(4);
}
}
private String getRenderPassName() { return "distantHorizons:DhFarFadeRenderer"; }
//endregion
}
#endif
@@ -1,274 +0,0 @@
/*
* 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.common.render.blaze.postProcessing;
#if MC_VER <= MC_1_21_10
public class BlazeDhFogRenderer {}
#else
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.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.DhMat4f;
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 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.
*/
public class BlazeDhFogRenderer implements IDhFogRenderer
{
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 BlazeDhFogRenderer INSTANCE = new BlazeDhFogRenderer();
private BlazeDhApplyRenderer applyRenderer;
private RenderPipeline pipeline;
private boolean init = false;
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("dh_fog_frag_uniform");
private GpuBuffer vboGpuBuffer;
private final BlazeTextureWrapper fogColorTextureWrapper = BlazeTextureWrapper.createColor("dh_fog_color_texture");
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
private final BlazeTextureWrapper fogDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_fog_depth_texture");
//=============//
// constructor //
//=============//
//region
private BlazeDhFogRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
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",
blendFunc,
"apply/blaze/vert", "apply/blaze/frag"
);
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("fog_render");
pipelineBuilder.withVertexShader("fog/blaze/vert");
pipelineBuilder.withFragmentShader("fog/blaze/frag");
pipelineBuilder.withSampler("uDhDepthTexture");
pipelineBuilder.withUniformBuffer("fragUniformBlock");
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("FogRenderer");
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams, DhApiFogRenderParam fogRenderParams)
{
this.tryInit();
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
{
return;
}
this.fogColorTextureWrapper.tryCreateOrResize();
this.fogDepthTextureWrapper.tryCreateOrResize();
{
// create data //
int lodDrawDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH;
DhMat4f inverseMvmProjMatrix = new DhMat4f(renderParams.dhMvmProjMatrix);
inverseMvmProjMatrix.invert();
EDhApiHeightFogMixMode heightFogMixingMode = fogRenderParams.getHeightFogMixingMode();
boolean heightFogEnabled =
heightFogMixingMode != EDhApiHeightFogMixMode.SPHERICAL
&& heightFogMixingMode != EDhApiHeightFogMixMode.CYLINDRICAL;
boolean useSphericalFog = heightFogMixingMode == EDhApiHeightFogMixMode.SPHERICAL;
Color fogColor = fogRenderParams.getFogColor();
// upload data //
this.fragUniformBufferWrapper
// fog uniforms
.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 / renderParams.clientLevelWrapper.getMaxHeight()) //uFogVerticalScale
.putInt(0) //uFogDebugMode // 0 = normal // 1 = render everything with fog color // 7 = use debug rendering
.putInt(fogRenderParams.getFarFogFalloff().value) //uFogFalloffType
// fog config
.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(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(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)renderParams.exactCameraPosition.y) // uCameraBlockYPos
.putMat4f(inverseMvmProjMatrix) // uInvMvmProj
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
.finishAndUpload()
;
}
this.renderFogToTexture();
this.applyRenderer.render(this.fogColorTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.texture);
}
private void renderFogToTexture()
{
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
this.fogColorTextureWrapper,
this.fogDepthTextureWrapper))
{
renderPassWrapper.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper);
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.draw(/*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:FogRenderer"; }
//endregion
}
#endif
@@ -1,253 +0,0 @@
/*
* 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.common.render.blaze.postProcessing;
#if MC_VER <= MC_1_21_10
public class BlazeDhSsaoRenderer {}
#else
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.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.DhMat4f;
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 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
{
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();
public static final BlazeDhSsaoRenderer INSTANCE = new BlazeDhSsaoRenderer();
private BlazeDhApplyRenderer applyRenderer;
private RenderPipeline pipeline;
private boolean init = false;
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("fragUniformBlock");
private final BlazeUniformBufferWrapper applyFragUniformBufferWrapper = new BlazeUniformBufferWrapper("applyFragUniformBlock");
private GpuBuffer vboGpuBuffer;
private final BlazeTextureWrapper ssaoColorTextureWrapper = BlazeTextureWrapper.createColor("dh_ssao_color_texture");
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
private final BlazeTextureWrapper ssaoDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_ssao_depth_texture");
//=============//
// constructor //
//=============//
//region
private BlazeDhSsaoRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
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",
blendFunc,
"apply/blaze/vert", "ssao/blaze/apply",
/*uniforms*/ new String[] { "applyFragUniformBlock" }
);
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("ssao_render");
pipelineBuilder.withVertexShader("ssao/blaze/vert");
pipelineBuilder.withFragmentShader("ssao/blaze/frag");
pipelineBuilder.withSampler("uDhDepthTexture");
pipelineBuilder.withUniformBuffer("fragUniformBlock");
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McSsao");
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
{
return;
}
// textures
this.ssaoColorTextureWrapper.tryCreateOrResize();
this.ssaoDepthTextureWrapper.tryCreateOrResize();
// frag uniforms
{
// create data //
DhMat4f projMatrix = new DhMat4f(renderParams.dhProjectionMatrix);
DhMat4f invertedProjMatrix = new DhMat4f(renderParams.dhProjectionMatrix);
invertedProjMatrix.invert();
// upload data //
this.fragUniformBufferWrapper
.putInt(6) // uSampleCount
.putFloat(4.0f) // uRadius
.putFloat(0.2f) // uStrength
.putFloat(0.25f) // uMinLight
.putFloat(0.02f) // uBias
.putFloat(1_600.0f) // uFadeDistanceInBlocks
.putMat4f(invertedProjMatrix)
.putMat4f(projMatrix)
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
.finishAndUpload()
;
}
// apply frag uniforms
{
// create data //
float viewWidth = (float)MC_RENDER.getTargetFramebufferViewportWidth();
float viewHeight = (float)MC_RENDER.getTargetFramebufferViewportHeight();
float nearClipPlane = RenderUtil.getNearClipPlaneInBlocks();
float farClipPlane = RenderUtil.getFarClipPlaneDistanceInBlocks();
// upload data //
this.applyFragUniformBufferWrapper
.putVec2f(viewWidth, viewHeight) // uViewSize
.putInt(2) // uBlurRadius
.putFloat(nearClipPlane) // uNearClipPlane
.putFloat(farClipPlane) // uFarClipPlane
.finishAndUpload()
;
}
this.renderSsaoToTexture();
this.applyRenderer.setUniform("applyFragUniformBlock", this.applyFragUniformBufferWrapper);
this.applyRenderer.render(this.ssaoColorTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.texture);
}
private void renderSsaoToTexture()
{
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
this.ssaoColorTextureWrapper,
this.ssaoDepthTextureWrapper))
{
renderPassWrapper.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper);
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.draw(4);
}
}
private String getRenderPassName() { return "distantHorizons:SsaoRenderer"; }
//endregion
}
#endif
@@ -1,237 +0,0 @@
/*
* 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.common.render.blaze.postProcessing;
#if MC_VER <= MC_1_21_10
public class BlazeVanillaFadeRenderer {}
#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.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.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.DhMat4f;
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;
/**
* Fades the vanilla chunks
* into DH's LODs.
*/
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 final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("fragUniformBlock");
private GpuBuffer vboGpuBuffer;
public final BlazeTextureWrapper fadeColorTextureWrapper = BlazeTextureWrapper.createColor("DhVanillaFadeColorTexture");
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
private final BlazeTextureWrapper fadeDepthTextureWrapper = BlazeTextureWrapper.createDepth("DhVanillaFadeDepthTexture");
public final BlazeTextureViewWrapper mcDepthTextureWrapper = new BlazeTextureViewWrapper();
public final BlazeTextureViewWrapper mcColorTextureWrapper = new BlazeTextureViewWrapper();
//=============//
// constructor //
//=============//
//region
private BlazeVanillaFadeRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("vanilla_fade");
pipelineBuilder.withVertexShader("fade/blaze/vert");
pipelineBuilder.withFragmentShader("fade/blaze/vanilla_fade");
pipelineBuilder.withSampler("uMcDepthTexture");
pipelineBuilder.withSampler("uCombinedMcDhColorTexture");
pipelineBuilder.withSampler("uDhDepthTexture");
pipelineBuilder.withSampler("uDhColorTexture");
pipelineBuilder.withUniformBuffer("fragUniformBlock");
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("VanillaFadeRenderer");
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
{
return;
}
// textures
this.fadeColorTextureWrapper.tryCreateOrResize();
this.fadeDepthTextureWrapper.tryCreateOrResize();
this.mcDepthTextureWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getDepthTexture());
this.mcColorTextureWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture());
{
// create data //
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
// this added value prevents the near clip plane and discard circle from touching, which looks bad
dhNearClipDistance += 16f;
// measured in blocks
// these multipliers in James' tests should provide a fairly smooth transition
// without having underdraw issues
float fadeStartDistance = dhNearClipDistance * 1.5f;
float fadeEndDistance = dhNearClipDistance * 1.9f;
DhMat4f inverseMcModelViewProjectionMatrix = new DhMat4f(renderParams.mcProjectionMatrix);
inverseMcModelViewProjectionMatrix.multiply(renderParams.mcModelViewMatrix);
inverseMcModelViewProjectionMatrix.invert();
DhMat4f inverseMcMvmProjMatrix = inverseMcModelViewProjectionMatrix;
DhMat4f inverseDhModelViewProjectionMatrix = new DhMat4f(renderParams.dhProjectionMatrix);
inverseDhModelViewProjectionMatrix.multiply(renderParams.dhModelViewMatrix);
inverseDhModelViewProjectionMatrix.invert();
DhMat4f inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix;
// upload data //
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) // uDhInvMvmProj
.putMat4f(inverseMcMvmProjMatrix) // uMcInvMvmProj
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
.finishAndUpload()
;
}
this.renderFadeToTexture();
BlazeDhCopyRenderer.INSTANCE.render(this.fadeColorTextureWrapper, this.mcColorTextureWrapper);
}
private void renderFadeToTexture()
{
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
this.fadeColorTextureWrapper,
this.fadeDepthTextureWrapper))
{
renderPassWrapper.bindTexture("uMcDepthTexture", this.mcDepthTextureWrapper);
renderPassWrapper.bindTexture("uCombinedMcDhColorTexture", this.mcColorTextureWrapper);
renderPassWrapper.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper);
renderPassWrapper.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper);
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.draw(/*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:VanillaFadeRenderer"; }
//endregion
}
#endif
@@ -1,190 +0,0 @@
/*
* 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.common.render.blaze.test;
#if MC_VER <= MC_1_21_10
public class BlazeDhTestTriangleRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.PolygonMode;
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.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTestTriangleRenderer;
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;
#if MC_VER <= MC_1_21_11
#else
import com.mojang.blaze3d.pipeline.DepthStencilState;
import com.mojang.blaze3d.platform.CompareOp;
#endif
/**
* Renders the OpenGL/Vulkan triangle
* to the center of the screen to confirm DH's
* apply shader is running correctly
*/
public class BlazeDhTestTriangleRenderer implements IDhTestTriangleRenderer
{
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();
public static final BlazeDhTestTriangleRenderer INSTANCE = new BlazeDhTestTriangleRenderer();
private RenderPipeline pipeline;
private boolean init = false;
public final BlazeTextureViewWrapper mcColorTextureViewWrapper = new BlazeTextureViewWrapper();
public final BlazeTextureViewWrapper mcDepthTextureViewWrapper = new BlazeTextureViewWrapper();
private GpuBuffer vboGpuBuffer;
//=============//
// constructor //
//=============//
//region
private BlazeDhTestTriangleRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withName("triangle_test");
pipelineBuilder.withVertexShader("test/blaze/vert");
pipelineBuilder.withFragmentShader("test/blaze/frag");
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
.add("vColor", BlazeDhVertexFormatUtil.RGBA_FLOAT_COLOR)
.build();
pipelineBuilder.withVertexFormat(vertexFormat);
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLES);
}
this.pipeline = pipelineBuilder.build();
this.uploadVertexData();
}
private void uploadVertexData()
{
// vertices for the OpenGL/Vulkan Triangle
float[] vertices = new float[]
{
// PosX,Y, ColorR,G,B,A
-0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f,
};
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int size = vertices.length * Float.BYTES;
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getRenderPassName, usage, size);
{
int offset = 0;
int length = vertices.length * Float.BYTES;
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, offset, length);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * Float.BYTES);
// Fill buffer with vertices.
byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer.asFloatBuffer().put(vertices);
byteBuffer.rewind();
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
}
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
this.mcColorTextureViewWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture());
this.mcDepthTextureViewWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getDepthTexture());
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
this::getRenderPassName,
this.mcColorTextureViewWrapper,
this.mcDepthTextureViewWrapper))
{
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
renderPassWrapper.setPipeline(this.pipeline);
renderPassWrapper.draw(3);
}
}
private String getRenderPassName() { return "distantHorizons:DhTestRenderer"; }
//endregion
}
#endif
@@ -1,158 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.util;
#if MC_VER <= MC_1_21_10
public class BlazeDhVertexFormatUtil {}
#else
import com.mojang.blaze3d.vertex.VertexFormatElement;
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;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
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
*/
@SuppressWarnings("DataFlowIssue") // ignore null setter warnings in the static constructor (those will only be null if the render API is GL and in that case we should never use these objects)
public class BlazeDhVertexFormatUtil
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@NotNull public static final VertexFormatElement SCREEN_POS;
@NotNull public static final VertexFormatElement RGBA_FLOAT_COLOR;
@NotNull public static final VertexFormatElement SHORT_XYZ_POS;
@NotNull public static final VertexFormatElement BYTE_PAD;
/** contains light and micro-offset */
@NotNull public static final VertexFormatElement META;
@NotNull public static final VertexFormatElement RGBA_UBYTE_COLOR;
@NotNull public static final VertexFormatElement IRIS_MATERIAL;
@NotNull public static final VertexFormatElement IRIS_NORMAL;
@NotNull public static final VertexFormatElement FLOAT_XYZ_POS;
static
{
EDhApiRenderingEngine renderingApi = Config.Client.Advanced.Graphics.Experimental.renderingEngine.get();
if (renderingApi == EDhApiRenderingEngine.AUTO)
{
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
renderingApi = versionConstants.getDefaultRenderingEngine();
}
boolean register = (renderingApi == EDhApiRenderingEngine.BLAZE_3D);
if (register)
{
LOGGER.debug("Attempting to register ["+VertexFormatElement.class.getSimpleName()+"]...");
try
{
#if MC_VER <= MC_1_21_11
SCREEN_POS = VertexFormatElement.register(/*id*/22, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, /*count*/ 2);
RGBA_FLOAT_COLOR = VertexFormatElement.register(/*id*/23, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.COLOR, /*count*/ 4);
SHORT_XYZ_POS = VertexFormatElement.register(/*id*/24, /*index*/0, VertexFormatElement.Type.USHORT, VertexFormatElement.Usage.POSITION, /*count*/ 3);
BYTE_PAD = VertexFormatElement.register(/*id*/25, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
META = VertexFormatElement.register(/*id*/26, /*index*/0, VertexFormatElement.Type.USHORT, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
RGBA_UBYTE_COLOR = VertexFormatElement.register(/*id*/27, /*index*/0, VertexFormatElement.Type.UBYTE, VertexFormatElement.Usage.COLOR, /*count*/ 4);
IRIS_MATERIAL = VertexFormatElement.register(/*id*/28, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
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);
#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);
SHORT_XYZ_POS = VertexFormatElement.register(/*id*/24, /*index*/0, VertexFormatElement.Type.USHORT, false, /*count*/ 3);
BYTE_PAD = VertexFormatElement.register(/*id*/25, /*index*/0, VertexFormatElement.Type.BYTE, false, /*count*/ 1);
META = VertexFormatElement.register(/*id*/26, /*index*/0, VertexFormatElement.Type.USHORT, false, /*count*/ 1);
RGBA_UBYTE_COLOR = VertexFormatElement.register(/*id*/27, /*index*/0, VertexFormatElement.Type.UBYTE, true, /*count*/ 4);
IRIS_MATERIAL = VertexFormatElement.register(/*id*/28, /*index*/0, VertexFormatElement.Type.BYTE, false, /*count*/ 1);
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)
{
String message = "Unable to register one or more ["+VertexFormatElement.class.getSimpleName()+"] this is likely caused by another mod registering their own custom ["+VertexFormatElement.class.getSimpleName()+"]'s. This should be fixed in the next major Minecraft version.";
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
mc.crashMinecraft(message, new Exception(message, e));
// here to make the compiler happy, the process should shut down before this
throw new RuntimeException(e);
}
LOGGER.debug("Successfully registered ["+VertexFormatElement.class.getSimpleName()+"].");
}
else
{
// set to null so we can fail fast with a null pointer if we ever attempt to incorrectly use these
SCREEN_POS = null;
RGBA_FLOAT_COLOR = null;
SHORT_XYZ_POS = null;
BYTE_PAD = null;
META = null;
RGBA_UBYTE_COLOR = null;
IRIS_MATERIAL = null;
IRIS_NORMAL = null;
FLOAT_XYZ_POS = null;
}
}
}
#endif
@@ -1,82 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.util;
#if MC_VER <= MC_1_21_10
public class BlazePostProcessUtil {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
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;
import java.util.function.Supplier;
/** Contains code that's used by all post-processing effects. */
public class BlazePostProcessUtil
{
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
// vertices for a full-screen quad
private static final float[] VERTICES = new float[]
{
// PosX,Y,
-1f, -1f,
1f, -1f,
1f, 1f,
-1f, 1f,
};
//=========//
// methods //
//=========//
//region
public static GpuBuffer createAndUploadScreenVertexData(String name)
{
Supplier<String> labelSupplier = () -> "distantHorizons:"+name;
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int size = VERTICES.length * Float.BYTES;
GpuBuffer vboGpuBuffer = GPU_DEVICE.createBuffer(labelSupplier, usage, size);
{
int length = VERTICES.length * Float.BYTES;
GpuBufferSlice bufferSlice = new GpuBufferSlice(vboGpuBuffer, /*offset*/ 0, length);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(VERTICES.length * Float.BYTES);
// Fill buffer with vertices.
byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer.asFloatBuffer().put(VERTICES);
byteBuffer.rewind();
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
}
return vboGpuBuffer;
}
public static VertexFormat createVertexFormat()
{
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
.build();
return vertexFormat;
}
//endregion
}
#endif
@@ -1,46 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.util;
#if MC_VER <= MC_1_21_10
public class BlazeUniformUtil {}
#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.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
public class BlazeUniformUtil
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static GpuBuffer createBuffer(String uniformName, int size, GpuBuffer vboGpuBuffer)
{
// create VBO if needed
if (vboGpuBuffer == null
|| vboGpuBuffer.size() < size)
{
if (vboGpuBuffer != null)
{
vboGpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX
| GpuBuffer.USAGE_UNIFORM;
vboGpuBuffer = GPU_DEVICE.createBuffer(() -> uniformName, usage, size);
}
return vboGpuBuffer;
}
}
#endif
@@ -1,58 +0,0 @@
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
@@ -1,163 +0,0 @@
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.Optional;
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
@@ -1,445 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers;
#if MC_VER <= MC_1_21_10
public class RenderPipelineBuilderWrapper {}
#else
import com.mojang.blaze3d.pipeline.*;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.resources.Identifier;
#if MC_VER <= MC_1_21_11
import com.mojang.blaze3d.platform.DepthTestFunction;
#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
{
public static final String NAME_PREFIX = "distanthorizons:";
private static final String SHADER_RESOURCE_FOLDER = "assets/distanthorizons/shaders/";
private static final ClassLoader CLASS_LOADER = RenderPipelineBuilderWrapper.class.getClassLoader();
private final RenderPipeline.Builder blazePipelineBuilder;
// variables for specific builder options should be put next to their builder methods for simpler organization
//=============//
// constructor //
//=============//
//region
public RenderPipelineBuilderWrapper()
{
this.blazePipelineBuilder = RenderPipeline.builder();
}
//endregion
//==========//
// building //
//==========//
//region
private boolean writeDepth = false;
public RenderPipelineBuilderWrapper withDepthWrite(boolean write)
{
this.writeDepth = write;
return this;
}
private boolean writeColor = false;
public RenderPipelineBuilderWrapper withColorWrite(boolean write)
{
this.writeColor = write;
return this;
}
private BlendFunction blendFunction = null;
public RenderPipelineBuilderWrapper withBlend(BlendFunction blendFunction)
{
this.blendFunction = blendFunction;
return this;
}
public RenderPipelineBuilderWrapper withoutBlend()
{
this.blendFunction = null;
return this;
}
private EDhDepthTest depthTest;
public RenderPipelineBuilderWrapper withDepthTest(EDhDepthTest depthTest)
{
this.depthTest = depthTest;
return this;
}
public RenderPipelineBuilderWrapper withFaceCulling(boolean culling)
{
this.blazePipelineBuilder.withCull(culling);
return this;
}
public RenderPipelineBuilderWrapper withPolygonMode(EDhPolygonMode dhMode)
{
PolygonMode blazeMode;
switch (dhMode)
{
case FILL:
blazeMode = PolygonMode.FILL;
break;
case WIREFRAME:
blazeMode = PolygonMode.WIREFRAME;
break;
default:
throw new UnsupportedOperationException("No polygonMode defined for type ["+dhMode+"].");
}
this.blazePipelineBuilder.withPolygonMode(blazeMode);
return this;
}
public RenderPipelineBuilderWrapper withName(String name) throws IllegalArgumentException
{
// Identifiers must be of a specific format
if (!isValidIdentifier(name))
{
throw new IllegalArgumentException("Non [a-z0-9/._-] character in name: ["+name+"].");
}
this.blazePipelineBuilder.withLocation(Identifier.parse(NAME_PREFIX + name));
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;
}
private VertexFormat vertexFormat = null;
public RenderPipelineBuilderWrapper withVertexFormat(VertexFormat vertexFormat)
{
this.vertexFormat = vertexFormat;
return this;
}
private EDhVertexMode vertexMode = null;
public RenderPipelineBuilderWrapper withVertexMode(EDhVertexMode vertexMode)
{
this.vertexMode = vertexMode;
return this;
}
public RenderPipelineBuilderWrapper withVertexShader(String scriptResourcePath) { return this.withShader(EDhShaderType.VERTEX, scriptResourcePath); }
public RenderPipelineBuilderWrapper withFragmentShader(String scriptResourcePath) { return this.withShader(EDhShaderType.FRAGMENT, scriptResourcePath); }
private RenderPipelineBuilderWrapper withShader(EDhShaderType shaderType, String scriptResourcePath)
{
String fullShaderResourcePath = SHADER_RESOURCE_FOLDER + scriptResourcePath + shaderType.fileExtension;
// confirm the shader file exists
try (InputStream scriptListInputStream = CLASS_LOADER.getResourceAsStream(fullShaderResourcePath))
{
if (scriptListInputStream == null)
{
throw new NullPointerException("Failed to find the SQL Script list file [" + fullShaderResourcePath + "], no auto update scripts can be run.");
}
}
catch (IOException e)
{
// shouldn't happen, but just in case
throw new RuntimeException("Unexpected issue closing resource stream for shader type: ["+shaderType+"] at: ["+fullShaderResourcePath+"], error: ["+e.getMessage()+"].", e);
}
if (shaderType == EDhShaderType.VERTEX)
{
this.blazePipelineBuilder.withVertexShader(Identifier.parse(NAME_PREFIX + scriptResourcePath));
}
else
{
this.blazePipelineBuilder.withFragmentShader(Identifier.parse(NAME_PREFIX + scriptResourcePath));
}
return this;
}
//endregion
//=====//
// end //
//=====//
//region
public RenderPipeline build() throws UnsupportedOperationException
{
// depth/color
{
#if MC_VER <= MC_1_21_11
this.blazePipelineBuilder.withDepthWrite(this.writeDepth);
this.blazePipelineBuilder.withColorWrite(this.writeColor);
if (this.blendFunction != null)
{
this.blazePipelineBuilder.withBlend(this.blendFunction);
}
else
{
this.blazePipelineBuilder.withoutBlend();
}
DepthTestFunction depthTestFunction;
switch (this.depthTest)
{
case NONE:
depthTestFunction = DepthTestFunction.NO_DEPTH_TEST;
break;
case LESS:
depthTestFunction = DepthTestFunction.LESS_DEPTH_TEST;
break;
default:
throw new UnsupportedOperationException("No depth test defined for type ["+this.depthTest+"].");
}
this.blazePipelineBuilder.withDepthTestFunction(depthTestFunction);
#else
CompareOp compareOp;
switch (this.depthTest)
{
case NONE:
compareOp = CompareOp.ALWAYS_PASS;
break;
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
}
// vertex format
{
#if MC_VER <= MC_26_1_2
VertexFormat.Mode blazeVertexMode;
switch (this.vertexMode)
{
case TRIANGLES:
blazeVertexMode = VertexFormat.Mode.TRIANGLES;
break;
case TRIANGLE_FAN:
blazeVertexMode = VertexFormat.Mode.TRIANGLE_FAN;
break;
case LINES:
blazeVertexMode = VertexFormat.Mode.DEBUG_LINES;
break;
default:
throw new UnsupportedOperationException("No vertex mode defined for type ["+this.vertexMode+"].");
}
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();
}
//endregion
//================//
// helper methods //
//================//
//region
private static boolean isValidIdentifier(String identifier)
{
for (int i = 0; i < identifier.length(); i++)
{
char ch = identifier.charAt(i);
if (!isValidNamespaceChar(ch))
{
return false;
}
}
return true;
}
private static boolean isValidNamespaceChar(final char ch)
{
return ch == '_'
|| ch == '-'
// only lower case characters
|| (ch >= 'a' && ch <= 'z')
|| (ch >= '0' && ch <= '9')
|| ch == '.';
}
//endregion
//================//
// helper classes //
//================//
//region
public enum EDhPolygonMode
{
FILL,
WIREFRAME;
}
public enum EDhVertexMode
{
TRIANGLES,
TRIANGLE_FAN,
LINES;
}
public enum EDhDepthTest
{
NONE,
GREATER,
LESS;
}
private enum EDhShaderType
{
FRAGMENT(".fsh"),
VERTEX(".vsh");
public final String fileExtension;
EDhShaderType(String fileExtension)
{
this.fileExtension = fileExtension;
}
}
//endregion
}
#endif
@@ -1,210 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.buffer;
#if MC_VER <= MC_1_21_10
public class BlazeVertexBufferWrapper {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.IndexBufferBuilder;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
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.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicInteger;
public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final AbstractDhRenderApiDefinition RENDER_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private static final AtomicInteger BUFFER_COUNT_REF = new AtomicInteger(0);
public final String name;
public String getName() { return this.name; }
public GpuBuffer vertexGpuBuffer = null;
public int vertexCount = -1;
public int indexCount = -1;
public boolean uploaded = false;
private GpuBuffer indexGpuBuffer = null;
private static GpuBuffer GLOBAL_INDEX_GPU_BUFFER = null;
public GpuBuffer getIndexGpuBuffer()
{
if (RENDER_DEF.useSingleIbo())
{
return GLOBAL_INDEX_GPU_BUFFER;
}
else
{
return this.indexGpuBuffer;
}
}
//=============//
// constructor //
//=============//
//region
static
{
if (RENDER_DEF.useSingleIbo())
{
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Global IBO Creation", () ->
{
int maxSize = LodQuadBuilder.getMaxBufferByteSize();
int maxVertexCount = maxSize / LodQuadBuilder.BYTES_PER_VERTEX;
int maxQuadCount = (maxVertexCount / 4);
ByteBuffer indexBuffer = IndexBufferBuilder.createBuffer(maxQuadCount);
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_INDEX;
GLOBAL_INDEX_GPU_BUFFER = GPU_DEVICE.createBuffer(BlazeVertexBufferWrapper::getIndexBufferName, usage, indexBuffer.capacity());
GpuBufferSlice bufferSlice = new GpuBufferSlice(GLOBAL_INDEX_GPU_BUFFER, /*offset*/ 0, indexBuffer.capacity());
COMMAND_ENCODER.writeToBuffer(bufferSlice, indexBuffer);
});
}
}
public BlazeVertexBufferWrapper(String name) { this.name = name; }
//endregion
//========//
// upload //
//========//
//region
@Override
public void uploadVertexBuffer(ByteBuffer vertexBuffer, int vertexCount)
{
int oldVertexCount = this.vertexCount;
this.vertexCount = vertexCount;
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
this.indexCount = (int)(vertexCount * 1.5);
this.uploaded = true;
if (this.vertexGpuBuffer == null
// recreating if the size changes is always necessary (even if we only need a smaller amount)
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|| oldVertexCount != vertexCount)
{
if (this.vertexGpuBuffer == null)
{
BUFFER_COUNT_REF.incrementAndGet();
//LOGGER.info("Create, count: ["+BUFFER_COUNT_REF.get()+"]");
}
if (this.vertexGpuBuffer != null)
{
this.vertexGpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int byteSize = (vertexBuffer.limit() - vertexBuffer.position());
this.vertexGpuBuffer = GPU_DEVICE.createBuffer(this::getName, usage, byteSize);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertexGpuBuffer, /*offset*/0, byteSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, vertexBuffer);
}
}
@Override
public void uploadIndexBuffer(ByteBuffer indexBuffer, int vertexCount)
{
int oldIndexCount = this.indexCount;
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
this.indexCount = (int)(vertexCount * 1.5);
if (RENDER_DEF.useSingleIbo())
{
// ignore index uploading when running a single IBO
return;
}
// recreating if the size changes is always necessary (even if we only need a smaller amount)
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
if (this.indexGpuBuffer == null
|| oldIndexCount != this.indexCount)
{
if (this.indexGpuBuffer == null)
{
BUFFER_COUNT_REF.incrementAndGet();
}
if (this.indexGpuBuffer != null)
{
this.indexGpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_INDEX;
this.indexGpuBuffer = GPU_DEVICE.createBuffer(BlazeVertexBufferWrapper::getIndexBufferName, usage, indexBuffer.capacity());
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, /*offset*/ 0, indexBuffer.capacity());
COMMAND_ENCODER.writeToBuffer(bufferSlice, indexBuffer);
}
}
private static String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
if (this.vertexGpuBuffer != null)
{
BUFFER_COUNT_REF.decrementAndGet();
this.vertexGpuBuffer.close();
}
if (this.indexGpuBuffer != null)
{
BUFFER_COUNT_REF.decrementAndGet();
this.indexGpuBuffer.close();
}
//LOGGER.info("Close, count: ["+BUFFER_COUNT_REF.get()+"]");
}
//endregion
}
#endif
@@ -1,75 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.texture;
#if MC_VER <= MC_1_21_10
public class BlazeTextureViewWrapper {}
#else
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.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import java.util.OptionalDouble;
public class BlazeTextureViewWrapper implements IDhBlazeTexture
{
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 GpuTextureView textureView = null;
public GpuTextureView getTextureView() { return this.textureView; }
private GpuSampler textureSampler = null;
public GpuSampler getTextureSampler() { return this.textureSampler; }
//=======//
// setup //
//=======//
//region
/** does nothing if the texture is already wrapped */
public void tryWrap(GpuTexture texture)
{
this.tryRecreateTextureView(texture);
this.tryCreateSampler();
}
private void tryRecreateTextureView(GpuTexture texture)
{
if (this.textureView == null
|| this.textureView.texture() != texture)
{
if (this.textureView != null)
{
this.textureView.close();
}
this.textureView = GPU_DEVICE.createTextureView(texture);
}
}
private void tryCreateSampler()
{
if (this.textureSampler == null)
{
this.textureSampler = GPU_DEVICE.createSampler(
AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V
FilterMode.LINEAR, FilterMode.LINEAR, // minFilter, magFilter
1, // maxAnisotropy
OptionalDouble.empty() // maxLod
);
}
}
//endregion
}
#endif
@@ -1,223 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.texture;
#if MC_VER <= MC_1_21_10
public class BlazeTextureWrapper {}
#else
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.coreapi.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import java.util.OptionalDouble;
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();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
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;
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;
//==============//
// constructors //
//==============//
//region
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,
#if MC_VER <= MC_26_1_2 TextureFormat #else GpuFormat #endif textureFormat
)
{
this.name = name;
this.textureFormat = textureFormat;
}
//endregion
//=========//
// getters //
//=========//
//region
public boolean isEmpty() { return this.texture == null; }
/** @return -1 if the texture is null */
public int getWidth() { return this.width; }
/** @return -1 if the texture is null */
public int getHeight() { return this.height; }
//endregion
//=======//
// setup //
//=======//
//region
/**
* does nothing if the texture is already created and the correct size
* @return true if the texture was (re)created
*/
public boolean tryCreateOrResize()
{
boolean textureChanged = this.tryCreateTexture();
this.tryCreateSampler();
return textureChanged;
}
private boolean tryCreateTexture()
{
int viewWidth = MC_RENDER.getTargetFramebufferViewportWidth();
int viewHeight = MC_RENDER.getTargetFramebufferViewportHeight();
if (this.texture != null
&& this.width == viewWidth
&& this.height == viewHeight)
{
// no changes needed
return false;
}
if (this.texture != null)
{
this.texture.close();
this.textureView.close();
}
this.width = viewWidth;
this.height = viewHeight;
int usage = GpuTexture.USAGE_COPY_DST
| GpuTexture.USAGE_TEXTURE_BINDING
| GpuTexture.USAGE_COPY_SRC
| GpuTexture.USAGE_RENDER_ATTACHMENT;
this.texture = GPU_DEVICE.createTexture(
this.name,
usage,
this.textureFormat,
viewWidth, viewHeight,
/*depthOrLayers*/ 1, /*mipLevels*/ 1
);
this.textureView = GPU_DEVICE.createTextureView(this.texture);
return true;
}
private void tryCreateSampler()
{
if (this.textureSampler == null)
{
this.textureSampler = GPU_DEVICE.createSampler(
AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V
FilterMode.LINEAR, FilterMode.LINEAR, // minFilter, magFilter
1, // maxAnisotropy
OptionalDouble.empty() // maxLod
);
}
}
//endregion
//==========//
// clearing //
//==========//
//region
/**
* Will throw an exception if not a color texture.
* @see ColorUtil#argbToInt
*/
public void clearColor(int clearArgbColor)
{
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
}
}
/** Will throw an exception if not a depth texture. */
public void clearDepth(float depth)
{
if (this.texture != null)
{
COMMAND_ENCODER.clearDepthTexture(this.texture, depth);
}
}
//endregion
}
#endif
@@ -1,17 +0,0 @@
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
@@ -1,61 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.uniform;
#if MC_VER <= MC_1_21_10
public class BlazeLodUniformBufferWrapper {}
#else
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.util.math.DhVec3f;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
public class BlazeLodUniformBufferWrapper extends BlazeUniformBufferWrapper implements ILodContainerUniformBufferWrapper
{
private boolean uploaded = false;
//=============//
// constructor //
//=============//
//region
public BlazeLodUniformBufferWrapper() { super(BlazeLodUniformBufferWrapper.class.getName()); }
//endregion
//========//
// upload //
//========//
//region
@Override
public void tryUpload(LodBufferContainer bufferContainer)
{
if (this.uploaded)
{
return;
}
DhVec3f modelOffset = new DhVec3f(
(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;
}
//endregion
}
#endif
@@ -1,237 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.uniform;
#if MC_VER <= MC_1_21_10
public class BlazeUniformBufferWrapper {}
#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.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.util.math.DhMat4f;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
public class BlazeUniformBufferWrapper implements AutoCloseable
{
private 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 String name;
/** measured in bytes */
private int bufferSize = 0;
private ByteBuffer cpuBuffer = 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;
//=============//
// constructor //
//=============//
//region
public BlazeUniformBufferWrapper(String name) { this.name = name; }
//endregion
//=================//
// element builder //
//=================//
//region
public BlazeUniformBufferWrapper putVec2f(float x, float y)
{
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(DhMat4f.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.recreateCpuBuffer();
createNewBuilder = true;
}
if (createNewBuilder)
{
this.uniformBufferBuilder = Std140Builder.intoBuffer(this.cpuBuffer);
}
}
private void recreateCpuBuffer()
{
ByteBuffer oldBuffer = this.cpuBuffer;
int size = calcBufferSize(this.uniformElementTypes);
this.cpuBuffer = ByteBuffer.allocateDirect(size);
this.cpuBuffer.order(ByteOrder.nativeOrder());
if (oldBuffer != null)
{
oldBuffer.position(0);
this.cpuBuffer.put(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();
}
public void finishAndUpload()
{
// 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)
{
this.bufferSlice = new GpuBufferSlice(this.gpuBuffer, 0, this.bufferSize);
}
// upload to GPU
this.cpuBuffer.position(0);
COMMAND_ENCODER.writeToBuffer(this.bufferSlice, this.cpuBuffer);
// clear the element tracking for next time
this.elementCount = 0;
this.uniformElementTypes.clear();
this.uniformBufferBuilder = null;
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
if (this.gpuBuffer != null)
{
this.gpuBuffer.close();
}
}
//endregion
//================//
// helper classes //
//================//
//region
private enum EUniformElement
{
VEC2f,
VEC3f,
VEC3i,
VEC4f,
MAT4f,
INT,
FLOAT,
}
//endregion
}
#endif
@@ -1,197 +0,0 @@
/*
* 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.common.render.openGl;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLIndexBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.util.math.DhMat4f;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Handles rendering the wireframe particles
* that are used for seeing what the system's doing.
*/
public class GlDhDebugWireframeRenderer extends AbstractDebugWireframeRenderer
{
public static GlDhDebugWireframeRenderer INSTANCE = new GlDhDebugWireframeRenderer();
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
// rendering setup
private GlShaderProgram basicShader;
private GLVertexBuffer vertexBuffer;
private GLIndexBuffer indexBuffer;
private GlAbstractVertexAttribute va;
private boolean init = false;
/** A box from 0,0,0 to 1,1,1 */
private static final float[] BOX_VERTICES = {
//region
// Pos x y z
0, 0, 0,
1, 0, 0,
1, 1, 0,
0, 1, 0,
0, 0, 1,
1, 0, 1,
1, 1, 1,
0, 1, 1,
//endregion
};
private static final int[] BOX_OUTLINE_INDICES = {
//region
0, 1,
1, 2,
2, 3,
3, 0,
4, 5,
5, 6,
6, 7,
7, 4,
0, 4,
1, 5,
2, 6,
3, 7,
//endregion
};
//=============//
// constructor //
//=============//
//region
private GlDhDebugWireframeRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.va = GlAbstractVertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec3Pointer(false));
this.va.completeAndCheck(Float.BYTES * 3);
this.basicShader = new GlShaderProgram(
"assets/distanthorizons/shaders/debug/gl/vert.vert",
"assets/distanthorizons/shaders/debug/gl/frag.frag",
"vPosition"
);
this.createBuffer();
}
private void createBuffer()
{
// box vertices
ByteBuffer boxVerticesBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES);
boxVerticesBuffer.order(ByteOrder.nativeOrder());
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
boxVerticesBuffer.rewind();
this.vertexBuffer = new GLVertexBuffer(false);
this.vertexBuffer.bind();
this.vertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
// outline vertex indexes
ByteBuffer boxOutlineBuffer = ByteBuffer.allocateDirect(BOX_OUTLINE_INDICES.length * Integer.BYTES);
boxOutlineBuffer.order(ByteOrder.nativeOrder());
boxOutlineBuffer.asIntBuffer().put(BOX_OUTLINE_INDICES);
boxOutlineBuffer.rewind();
this.indexBuffer = new GLIndexBuffer(false);
this.indexBuffer.uploadBuffer(boxOutlineBuffer, EDhApiGpuUploadMethod.DATA, BOX_OUTLINE_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
}
//endregion
//===========//
// rendering //
//===========//
//region
@Override
public void render(RenderParams renderParams)
{
this.init();
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
GLMC.enableDepthTest();
this.basicShader.bind();
this.va.bind();
this.va.bindBufferToAllBindingPoints(this.vertexBuffer.getId());
this.indexBuffer.bind();
super.render(renderParams);
// revert to prevent issues with the following passes
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
}
@Override
public void renderBox(Box box)
{
DhMat4f boxTransform = DhMat4f.createTranslateMatrix(box.minPos.x - this.camPosFloatThisFrame.x, box.minPos.y - this.camPosFloatThisFrame.y, box.minPos.z - this.camPosFloatThisFrame.z);
boxTransform.multiply(DhMat4f.createScaleMatrix(box.maxPos.x - box.minPos.x, box.maxPos.y - box.minPos.y, box.maxPos.z - box.minPos.z));
DhMat4f transformMatrix = this.dhMvmProjMatrixThisFrame.copy();
transformMatrix.multiply(boxTransform);
this.basicShader.setUniform(this.basicShader.getUniformLocation("uTransform"), transformMatrix);
this.basicShader.setUniform(this.basicShader.getUniformLocation("uColor"), box.color);
GL32.glDrawElements(GL32.GL_LINES, BOX_OUTLINE_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
}
//endregion
}
@@ -1,481 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShaderProgram;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiTextureCreatedParam;
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.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
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.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
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.IOptifineAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.opengl.GL32;
public class GlDhMetaRenderer implements IDhMetaRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
.build();
public static final DhLogger RATE_LIMITED_LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
.maxCountPerSecond(4)
.build();
public static final GlDhMetaRenderer INSTANCE = new GlDhMetaRenderer();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
private int activeFramebufferId = -1;
private int activeColorTextureId = -1;
private int activeDepthTextureId = -1;
private int textureWidth;
private int textureHeight;
// framebuffer and texture ID's for this renderer
private IDhApiFramebuffer framebuffer;
/** will be null if MC's framebuffer is being used since MC already has a color texture */
@Nullable
private GlDhColorTexture nullableColorTexture;
private GlDhDepthTexture depthTexture;
/**
* If true the {@link GlDhMetaRenderer#framebuffer} is the same as MC's.
* This should only be true in the case of Optifine so LODs won't be overwritten when shaders are enabled.
*/
private boolean usingMcFramebuffer = false;
private boolean renderObjectsCreated = false;
/** used in case there's an API override */
public IDhApiShaderProgram shaderProgramForThisFrame;
/** Older MC versions assume GL state is unchanged, so we must restore it after DH rendering */
#if MC_VER <= MC_1_12_2
private int previousBoundTextureId;
private int previousDepthFunc;
#endif
//============//
// pre render //
//============//
//region
@Override
public void runRenderPassSetup(RenderParams renderParams)
{
boolean firstPass =
(renderParams.renderPass == EDhApiRenderPass.OPAQUE
|| renderParams.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT);
if (!this.renderObjectsCreated)
{
boolean setupSuccess = this.createRenderObjects();
if (!setupSuccess)
{
// shouldn't normally happen, but just in case
return;
}
this.renderObjectsCreated = true;
}
this.shaderProgramForThisFrame = GlDhTerrainRenderer.INSTANCE.getTerrainShaderProgram();
IDhApiShaderProgram lodShaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiShaderProgram.class);
if (lodShaderProgramOverride != null && this.shaderProgramForThisFrame.overrideThisFrame())
{
this.shaderProgramForThisFrame = lodShaderProgramOverride;
}
this.setGLState(renderParams, firstPass);
this.bindLightmap(renderParams.lightmap);
}
private void setGLState(
DhApiRenderParam renderEventParam,
boolean firstPass)
{
#if MC_VER <= MC_1_12_2
this.previousBoundTextureId = GLMC.getActiveTexture();
this.previousDepthFunc = GLMC.getActiveDepthFunc();
#endif
//===================//
// framebuffer setup //
//===================//
// get the active framebuffer
IDhApiFramebuffer framebuffer = this.framebuffer;
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
if (framebufferOverride != null && framebufferOverride.overrideThisFrame())
{
framebuffer = framebufferOverride;
}
this.setActiveFramebufferId(framebuffer.getId());
framebuffer.bind();
//==========//
// bindings //
//==========//
// by default draw everything as triangles
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GLMC.enableFaceCulling();
GLMC.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ZERO);
GL32.glDisable(GL32.GL_SCISSOR_TEST);
// Enable depth test and depth mask
GLMC.enableDepthTest();
GLMC.glDepthFunc(GL32.GL_LESS);
GLMC.enableDepthMask();
// This is required for MC versions 1.21.5+
// due to MC updating the lightmap by changing the viewport size
GL32.glViewport(0, 0, this.textureWidth, this.textureHeight);
this.shaderProgramForThisFrame.bind();
//==========//
// uniforms //
//==========//
IDhApiShaderProgram shaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiShaderProgram.class);
if (shaderProgramOverride != null)
{
shaderProgramOverride.fillUniformData(renderEventParam);
}
this.shaderProgramForThisFrame.fillUniformData(renderEventParam);
//===============//
// texture setup //
//===============//
// resize the textures if needed
if (MC_RENDER.getTargetFramebufferViewportWidth() != this.textureWidth
|| MC_RENDER.getTargetFramebufferViewportHeight() != this.textureHeight)
{
// just resizing the textures doesn't work when Optifine is present,
// so recreate the textures with the new size instead
this.createAndBindTextures();
}
// set the active textures
int depthTextureId = this.depthTexture.getTextureId();
this.setActiveDepthTextureId(depthTextureId);
if (this.nullableColorTexture != null)
{
int colorTextureId = this.nullableColorTexture.getTextureId();
this.setActiveColorTextureId(colorTextureId);
}
else
{
// get MC's color texture
int colorTextureId = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
this.setActiveColorTextureId(colorTextureId);
}
// needs to be fired after all the textures have been created/bound
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderEventParam);
if (clearTextures)
{
GL32.glClearDepth(1.0);
float[] clearColorValues = new float[4];
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 1.0f);
if (this.usingMcFramebuffer && framebufferOverride == null)
{
// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
// don't clear the color texture, that removes the sky
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
}
else if (firstPass)
{
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
}
}
}
private boolean createRenderObjects()
{
if (this.renderObjectsCreated)
{
LOGGER.warn("Renderer setup called but it has already completed setup!");
return false;
}
// GLProxy should have already been created by this point, but just in case create it now
GLProxy.getInstance();
LOGGER.info("Setting up renderer");
// create or get the frame buffer
if (OPTIFINE_ACCESSOR != null)
{
// use MC/Optifine's default Framebuffer so shaders won't remove the LODs
int currentFramebufferId = MC_RENDER.getTargetFramebuffer();
this.framebuffer = new GlDhFramebuffer(currentFramebufferId);
this.usingMcFramebuffer = true;
}
else
{
// normal use case
this.framebuffer = new GlDhFramebuffer();
this.usingMcFramebuffer = false;
}
// create and bind the necessary textures
this.createAndBindTextures();
if(this.framebuffer.getStatus() != GL32.GL_FRAMEBUFFER_COMPLETE)
{
// This generally means something wasn't bound, IE missing either the color or depth texture
LOGGER.warn("Framebuffer ["+this.framebuffer.getId()+"] isn't complete.");
return false;
}
LOGGER.info("Renderer setup complete");
return true;
}
@SuppressWarnings( "deprecation" ) // done to ignore DhApiColorDepthTextureCreatedEvent
private void createAndBindTextures()
{
int oldWidth = this.textureWidth;
int oldHeight = this.textureHeight;
this.textureWidth = MC_RENDER.getTargetFramebufferViewportWidth();
this.textureHeight = MC_RENDER.getTargetFramebufferViewportHeight();
DhApiTextureCreatedParam textureCreatedParam = new DhApiTextureCreatedParam(
oldWidth, oldHeight,
this.textureWidth, this.textureHeight
);
// DhApiColorDepthTextureCreatedEvent needs to be kept around since old versions of Iris need it
ApiEventInjector.INSTANCE.fireAllEvents(DhApiColorDepthTextureCreatedEvent.class, new DhApiColorDepthTextureCreatedEvent.EventParam(textureCreatedParam));
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeColorDepthTextureCreatedEvent.class, textureCreatedParam);
// also update the framebuffer override if present
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
this.depthTexture = new GlDhDepthTexture(this.textureWidth, this.textureHeight, EGlDhDepthBufferFormat.DEPTH32F);
this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
if (framebufferOverride != null)
{
framebufferOverride.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
}
// if we are using MC's frame buffer, a color texture is already present and shouldn't need to be bound
if (!this.usingMcFramebuffer)
{
this.nullableColorTexture = GlDhColorTexture.builder()
.setDimensions(this.textureWidth, this.textureHeight)
.setInternalFormat(EGlDhInternalTextureFormat.RGBA8)
.setPixelType(EGlDhPixelType.UNSIGNED_BYTE)
.setPixelFormat(EGlDhPixelFormat.RGBA)
.build();
this.framebuffer.addColorAttachment(0, this.nullableColorTexture.getTextureId());
if (framebufferOverride != null)
{
framebufferOverride.addColorAttachment(0, this.nullableColorTexture.getTextureId());
}
}
else
{
this.nullableColorTexture = null;
}
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterColorDepthTextureCreatedEvent.class, textureCreatedParam);
}
//endregion
//=============//
// post render //
//=============//
//region
@Override
public void runRenderPassCleanup(RenderParams renderParams)
{
boolean runningDeferredPass = (renderParams.renderPass == EDhApiRenderPass.TRANSPARENT);
if (!runningDeferredPass)
{
//===================//
// optifine clean up //
//===================//
if (this.usingMcFramebuffer)
{
// If MC's framebuffer is being used the depth needs to be cleared to prevent rendering on top of MC.
// This should only happen when Optifine shaders are being used.
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
}
}
#if MC_VER <= MC_1_12_2
GLMC.glDepthFunc(previousDepthFunc);
#endif
this.unbindLightmap();
this.shaderProgramForThisFrame.unbind();
}
@Override
public void applyToMcTexture(RenderParams renderParams) { GlDhApplyShader.INSTANCE.render(renderParams); }
//endregion
//================//
// clear textures //
//================//
//region
@Override
public void clearDhDepthAndColorTextures(RenderParams renderParams)
{
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
boolean firstPass =
(renderParams.renderPass == EDhApiRenderPass.OPAQUE
|| renderParams.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT);
GL32.glClearDepth(1.0);
float[] clearColorValues = new float[4];
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 1.0f);
if (this.usingMcFramebuffer
&& framebufferOverride == null)
{
//// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
//// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
//this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
// don't clear the color texture, that removes the sky
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
}
else if (firstPass)
{
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
}
}
//endregion
//===============//
// API functions //
//===============//
//region
public void setActiveFramebufferId(int id) { this.activeFramebufferId = id; }
/** @return -1 if no frame buffer has been bound yet */
public int getActiveFramebufferId() { return this.activeFramebufferId; }
public void setActiveColorTextureId(int id)
{
this.activeColorTextureId = id;
DhApiRenderProxy.activeOpenGlDhColorTextureId = id;
}
/** @return -1 if no texture has been bound yet */
public int getActiveColorTextureId() { return this.activeColorTextureId; }
public void setActiveDepthTextureId(int id)
{
this.activeDepthTextureId = id;
DhApiRenderProxy.activeOpenGlDhDepthTextureId = id;
}
/** @return -1 if no texture has been bound yet */
public int getActiveDepthTextureId() { return this.activeDepthTextureId; }
//endregion
//================//
// helper methods //
//================//
//region
public void bindLightmap(ILightMapWrapper lightMapWrapper)
{
LightMapWrapper lightMap = (LightMapWrapper)lightMapWrapper;
GLMC.glActiveTexture(GL32.GL_TEXTURE0 + LightMapWrapper.GL_BOUND_INDEX);
GLMC.glBindTexture(lightMap.getOpenGlId());
}
public void unbindLightmap()
{
// strange that we don't call "glActiveTexture" here but since it's working James isn't going to change it right now (2026-03-10)
#if MC_VER <= MC_1_12_2
GLMC.glBindTexture(previousBoundTextureId);
#else
GLMC.glBindTexture(0);
#endif
}
//endregion
}

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