Compare commits

..

22 Commits

Author SHA1 Message Date
Ran 3f37f7f02a Update Readme.md 2022-04-17 17:00:53 +00:00
TomTheFurry a88feda9ec Fix it so it build 2022-04-04 15:47:49 +08:00
TomTheFurry 07b7ecb30a Maybe fixed the light again? 2022-04-04 12:01:01 +08:00
TomTheFurry 32bbe487c0 Fix dumb stuff costing performance on world gen 2022-04-03 16:02:06 +08:00
TomTheFurry b367e5c3aa Fix dumb stuff costing performance on world gen 2022-04-03 16:01:54 +08:00
TomTheFurry a43b2b69a6 Fix up big blocks missing side faces 2022-04-03 13:06:18 +08:00
James Seibel 2a1de6f579 add missing fabric libraries for sodium 2022-04-02 23:46:31 -05:00
James Seibel 7dadff4219 automatically copy lod.accesswidener when building
By default the fabric build folder needs this file to run, but it wasn't being copied over, now it should be.
2022-04-02 23:08:33 -05:00
James Seibel 07c53a02ca Add phosphor as an option to build.gradle 2022-04-02 23:06:57 -05:00
TomTheFurry 1e54885d88 Disabled framebuffer fix for now making optifine shaders to work again 2022-04-02 22:24:17 +08:00
TomTheFurry 68f4084ab0 Fix coolGi's java-8 port 2022-04-02 22:18:40 +08:00
TomTheFurry 6fa968e016 Make lightmap fix works with Optifine shaders? 2022-04-02 21:11:38 +08:00
TomTheFurry 93c2078724 Make lightmap fix works with Optifine shaders? 2022-04-02 21:09:39 +08:00
TomTheFurry 2289d898ce Update core. 2022-04-02 15:25:28 +08:00
TomTheFurry 15e5a04ffd Maybe fixed colormatic's mod compat? 2022-04-02 13:49:28 +08:00
TomTheFurry 150ba98a4e MacOS Patch Successful! + fix missing fabric api 2022-04-01 19:46:54 +08:00
coolGi2007 d9484c9df4 Why dose the readme still say preprocessor_test 2022-04-01 08:26:59 +00:00
James Seibel a92e09c2be Merge branch '1.18.X' of gitlab.com:jeseibel/minecraft-lod-mod into 1.18.X 2022-03-31 21:23:41 -05:00
James Seibel f7e1dc378f Fix the default folder selection if sub-dimensions are disabled 2022-03-31 21:23:38 -05:00
Ran f7b84b1909 It was nice knowing you fabric-api 2022-03-31 14:49:53 +06:00
Ran abae2f6358 I forgor 2022-03-31 14:35:03 +06:00
Ran e83939f1b2 Remove fabric api as a dependency 2022-03-31 14:30:41 +06:00
232 changed files with 11568 additions and 8325 deletions
+29 -6
View File
@@ -1,3 +1,31 @@
# eclipse
bin
*.launch
.settings
.metadata
.classpath
.project
# idea
out
*.ipr
*.iws
*.iml
.idea
# gradle
build
.gradle
# other
eclipse
run
# Files from Forge MDK
logs
forge*changelog.txt
.architectury-transformer/
build/
*.ipr
run/
@@ -8,7 +36,6 @@ out/
output/
bin/
libs/
.architectury-transformer/
.classpath
.project
@@ -18,7 +45,6 @@ classes/
.vscode
.settings
*.launch
hs_err_pid*
**/src/generated/
Merged/
@@ -27,7 +53,4 @@ Merged/
*.bak
# file genearated via MC version switching using preprocessor
build.properties
# This accesswidener is generated at runtime ant not needed
common/src/main/resources/lod.accesswidener
build.properties
+37 -143
View File
@@ -1,16 +1,10 @@
# use Eclipse's JDK
image: gradle:eclipse-temurin
# The ci should always use an unix/unix-like OS to work
# all stages need to be defined here
# Don't build the standalone jar yet because it isn't done yet
# - build_standalone
stages:
- build_19
- build_18_2
- build_18_1
- build_17_1
- build_16_5
- build_18_2
variables:
# Pull core when building
@@ -23,147 +17,47 @@ before_script:
- echo GE_JOB_ID=$CI_JOB_ID >> generate_jars.env
# The standalone build
#build_standalone:
# stage: build_standalone
# script:
# # make sure any previously merged jars are removed before running this job.
# # note: if the merged folder doesn't exist "rm -R Merged" will throw an error, which can be ignored
# # the "|| true" makes that step always succeed.
# - ./gradlew core:build --gradle-user-home cache/;
#
# # Copy the file with the shortest name to the root DistantHorizons.jar so it can be sent off
# - cp $(find core/build/libs/ | awk 'function base(f){sub(".*/", "", f); return f;} {print length(base($0)), $0}'| sort -n | head -2 | grep -P "[0-9][0-9] core/build/libs/*" | #sed -r "s/([0-9][0-9] )//g") DistantHorizons.jar
# # build using Java 16
# image: eclipse-temurin:16
# artifacts:
# name: "NightlyBuild_standalone-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
# paths:
# # Get the standalone jar
# - DistantHorizons.jar
# expire_in: 1 day
# # even if one build fails, upload the successful jars
# when: always
# cache:
# key: "gradleCache"
# policy: pull-push
# paths:
# - .gradle
# - cache/
# allow_failure: true
# 1.16.5 build
build_16_5:
stage: build_16_5
script:
# make sure any previously merged jars are removed before running this job.
# note: if the merged folder doesn't exist "rm -R Merged" will throw an error, which can be ignored
# the "|| true" makes that step always succeed.
- ./gradlew test --gradle-user-home cache/;
- ./gradlew build -PmcVer="1.16.5" --gradle-user-home cache/;
# build using Java 16
image: eclipse-temurin:16
artifacts:
name: "Merged_NightlyBuild_1_16_5-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
# relative to the root directory
- Merged
expire_in: 1 day
# even if one build fails, upload the successful jars
when: always
cache:
key: "gradleCache"
policy: pull-push
paths:
- .gradle
- cache/
allow_failure: true
# 1.17.1 build
build_17_1:
stage: build_17_1
script:
- ./gradlew test --gradle-user-home cache/;
- ./gradlew build -PmcVer="1.17.1" --gradle-user-home cache/;
image: eclipse-temurin:16
artifacts:
name: "Merged_NightlyBuild_1_17_1-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
- Merged
expire_in: 1 day
when: always
cache:
key: "gradleCache"
policy: pull-push
paths:
- .gradle
- cache/
allow_failure: true
# 1.18.1 build
build_18_1:
stage: build_18_1
script:
- ./gradlew test --gradle-user-home cache/;
- ./gradlew build -PmcVer="1.18.1" --gradle-user-home cache/;
# build using Java 17
image: eclipse-temurin:17
artifacts:
name: "Merged_NightlyBuild_1_18_1-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
- Merged
expire_in: 1 day
when: always
cache:
key: "gradleCache"
policy: pull-push
paths:
- .gradle
- cache/
allow_failure: true
stage: build_18_1
script:
- ./gradlew deleteMerged --gradle-user-home cache/; # make sure any previously merged jars are removed before running this job
- ./gradlew build -PmcVer=1.18.1 --gradle-user-home cache/;
- ./gradlew merge --gradle-user-home cache/;
# build using Java 17
image: eclipse-temurin:17
artifacts:
name: "Merged_NightlyBuild_1_18_1-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
# relative to the root directory
- Merged
expire_in: 1 day
cache:
key: "gradleCache"
policy: pull-push
paths:
- .gradle
- cache/
# 1.18.2 build
build_18_2:
stage: build_18_2
script:
- ./gradlew test --gradle-user-home cache/;
- ./gradlew build -PmcVer="1.18.2" --gradle-user-home cache/;
image: eclipse-temurin:17
artifacts:
name: "Merged_NightlyBuild_1_18_2-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
- Merged
expire_in: 1 day
when: always
cache:
key: "gradleCache"
policy: pull-push
paths:
- .gradle
- cache/
allow_failure: true
# 1.19 build
build_19:
stage: build_19
script:
- ./gradlew test --gradle-user-home cache/;
- ./gradlew build -PmcVer="1.19" --gradle-user-home cache/;
image: eclipse-temurin:17
artifacts:
name: "Merged_NightlyBuild_1_19-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
- Merged
expire_in: 1 day
when: always
cache:
key: "gradleCache"
policy: pull-push
paths:
- .gradle
- cache/
allow_failure: true
stage: build_18_2
script:
- ./gradlew deleteMerged --gradle-user-home cache/;
- ./gradlew build -PmcVer=1.18.2 --gradle-user-home cache/;
- ./gradlew merge --gradle-user-home cache/;
image: eclipse-temurin:17
artifacts:
name: "Merged_NightlyBuild_1_18_2-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
- Merged
expire_in: 1 day
cache:
key: "gradleCache"
policy: pull-push
paths:
- .gradle
- cache/
# unused deployment stage
+3 -2
View File
@@ -1,3 +1,4 @@
[submodule "coreSubProjects"]
path = coreSubProjects
[submodule "core"]
path = core
url = https://gitlab.com/jeseibel/distant-horizons-core.git
branch = main
-44
View File
@@ -1,44 +0,0 @@
# 1.16.5 version
java_version=8
minecraft_version=1.16.5
parchment_version=2022.03.06
compatible_minecraft_versions=["1.16.4", "1.16.5"]
# Fabric loader
fabric_loader_version=0.13.2
fabric_api_version=0.42.0+1.16
architectury_version=1.31.61
# Fabric mod versions
modmenu_version=1.16.22
starlight_version_fabric=
phosphor_version_fabric=
lithium_version=mc1.16.5-0.6.6
sodium_version=mc1.16.5-0.2.0
iris_version=1.16.x-v1.2.5
bclib_version=
immersive_portals_version =
# Fabric mod run
# 0 = Dont enable and dont run
# 1 = Can be refranced in code but dosnt run
# 2 = Can be refranced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_lithium=0
enable_sodium=1
enable_iris=0
enable_bclib=0
# Forge loader
forge_version=36.2.28
# Forge mod versions
starlight_version_forge=
terraforged_version=3285909
# Forge mod run
# 0 = Dont enable and dont run
# 1 = Can be refranced in code but dosnt run
# 2 = Can be refranced in code and runs in client
enable_starlight_forge=0
enable_terraforged=2
-44
View File
@@ -1,44 +0,0 @@
# 1.17.1 version
java_version=16
minecraft_version=1.17.1
parchment_version=2021.12.12
compatible_minecraft_versions=["1.17", "1.17.1"]
# Fabric loader
fabric_loader_version=0.13.2
fabric_api_version=0.46.1+1.17
architectury_version=2.10.9
# Fabric mod versions
modmenu_version=2.0.14
starlight_version_fabric=3442770
phosphor_version_fabric=
lithium_version=mc1.17.1-0.7.5
sodium_version=mc1.17.1-0.3.4
iris_version=1.17.x-v1.2.5
bclib_version=
immersive_portals_version = 0.14-1.17
# Fabric mod run
# 0 = Dont enable and dont run
# 1 = Can be refranced in code but dosnt run
# 2 = Can be refranced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_lithium=0
enable_sodium=1
enable_iris=0
enable_bclib=0
# Forge loader
forge_version=37.1.1
# Forge mod versions
starlight_version_forge=3457784
terraforged_version=
# Forge mod run
# 0 = Dont enable and dont run
# 1 = Can be refranced in code but dosnt run
# 2 = Can be refranced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
+4 -9
View File
@@ -1,21 +1,18 @@
# 1.18.1 version
# 1.18.1 version based stuff
java_version = 17
minecraft_version=1.18.1
parchment_version=2022.03.06
compatible_minecraft_versions=["1.18", "1.18.1"]
java_version = 17
# Fabric loader
fabric_loader_version=0.13.3
fabric_api_version=0.46.6+1.18
architectury_version=3.9.57
# Fabric mod versions
modmenu_version=3.0.1
starlight_version_fabric=3554912
phosphor_version_fabric=3573395
lithium_version=mc1.18.1-0.7.7
sodium_version=mc1.18.1-0.4.0-alpha6
iris_version=1.18.x-v1.2.5
sodium_version=3605309
iris_version=1.18.x-v1.1.4
bclib_version=1.2.5
immersive_portals_version = v1.0.4-1.18
@@ -34,11 +31,9 @@ architectury_version=3.9.57
forge_version=39.1.2
# Forge mod versions
starlight_version_forge=3559934
terraforged_version=
# Forge mod run
# 0 = Dont enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
+9 -15
View File
@@ -1,24 +1,21 @@
# 1.18.2 version based stuff
java_version = 17
# architectury_plugin_version = 3.4-SNAPSHOT
# dev_architectury_loom_version = 0.10.0-SNAPSHOT
minecraft_version=1.18.2
parchment_version=2022.03.13
compatible_minecraft_versions=["1.18.2"]
java_version = 17
# Fabric loader
fabric_loader_version=0.13.3
fabric_api_version=0.48.0+1.18.2
architectury_version=4.4.59
# Fabric mod versions
modmenu_version=3.1.0
starlight_version_fabric=3667443
phosphor_version_fabric=3573395
lithium_version=mc1.18.2-0.7.9
sodium_version=mc1.18.2-0.4.1
iris_version=1.18.x-v1.2.5
bclib_version=1.4.5
canvas_version=mc118:1.0.2397
immersive_portals_version = v1.4.9-1.18
sodium_version=3669187
iris_version=1.18.x-v1.2.2
immersive_portals_version = v1.0.4-1.18
bclib_version=0
# Fabric mod run
# 0 = Don't enable and don't run
@@ -29,18 +26,15 @@ architectury_version=4.4.59
enable_sodium=1
enable_lithium=0
enable_iris=0
enable_bclib=1
enable_canvas=0
enable_bclib=0
# Forge loader
forge_version=40.0.18
# Forge mod versions
starlight_version_forge=
terraforged_version=
starlight_version_forge=0
# Forge mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
-45
View File
@@ -1,45 +0,0 @@
java_version = 17
minecraft_version=1.19.2
parchment_version=2022.08.10
compatible_minecraft_versions=["1.19.2"]
# Fabric loader
fabric_loader_version=0.14.9
fabric_api_version=0.60.0+1.19.2
architectury_version=6.2.46
# Fabric mod versions
modmenu_version=4.0.6
starlight_version_fabric=
phosphor_version_fabric=
lithium_version=
sodium_version=mc1.19.2-0.4.4
iris_version=1.19.2-v1.3.1
bclib_version=1.4.5
immersive_portals_version =
canvas_version=mc119-1.0.2480
# Fabric mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_sodium=1
enable_lithium=0
enable_iris=0
enable_bclib=1
enable_canvas=0
# Forge loader
forge_version=43.1.1
# forge_version=43.1.34
# Forge mod versions
starlight_version_forge=0
terraforged_version=
# Forge mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
-46
View File
@@ -1,46 +0,0 @@
# 1.18.2 version based stuff
java_version = 17
minecraft_version=1.19
parchment_version=2022.08.10
compatible_minecraft_versions=["1.19"]
# Fabric loader
fabric_loader_version=0.14.7
fabric_api_version=0.55.3+1.19
architectury_version=5.6.24
# Fabric mod versions
modmenu_version=4.0.0
starlight_version_fabric=
phosphor_version_fabric=
lithium_version=
sodium_version=3820973
iris_version=1.19.x-v1.2.5
immersive_portals_version =
bclib_version=
canvas_version=mc118:1.0.2397
# Fabric mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_sodium=1
enable_lithium=0
enable_iris=0
enable_bclib=0
enable_canvas=0
# Forge loader
forge_version=41.0.19
# Forge mod versions
starlight_version_forge=0
terraforged_version=
# Forge mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
-165
View File
@@ -1,165 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
+45 -89
View File
@@ -1,4 +1,6 @@
# <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
# THIS VERSION IS NO LONGER MAINTAINED! ALL DEVELOPMENT HAVE BEEN MOVED OVER TO THE MAIN BRANCH
# <img src="https://gitlab.com/jeseibel/distant-horizons-core/-/raw/main/_logo%20files/LOD%20logo%20flat%20-%20with%20boarder.png" width="32"> Distant Horizons
> A mod that adds a Level of Detail System to Minecraft
@@ -9,109 +11,84 @@ This mod adds a Level Of Detail (LOD) system to Minecraft.\
This implementation renders simplified chunks outside the normal render distance\
allowing for an increased view distance without harming performance.
In other words: this mod lets you see farther without turning your game into a slide show.\
Or in other words: this mod lets you see farther without turning your game into a slide show.\
If you want to see a quick demo, check out a video covering the mod here:
<a href="https://youtu.be/_04BZ8W2bDM" target="_blank">![Minecraft Level Of Detail (LOD) mod - Alpha 1.6.3](https://cdn.ko-fi.com/cdn/useruploads/png_ef4d209d-50d9-462f-b31f-92e42ec3e260cover.jpg?v=c1097a5b-029c-4484-bec3-80ff58c5d239)</a>
<a href="https://www.youtube.com/watch?v=H2tnvEVbO1c" target="_blank">![Minecraft Level Of Detail (LOD) mod - Alpha 1.5](https://i.ytimg.com/vi_webp/H2tnvEVbO1c/mqdefault.webp)</a>
<br>
### Versions
## Mod and Library Versions
Architectury version: 3.4-SNAPSHOT\
Java Compiler plugin: Manifold Preprocessor
This branch supports the following versions of Minecraft:
#### 1.19 (WIP)
Supported MC versions: [1.19]\
Forge version: 41.0.19\
Fabric version: 0.14.7\
Fabric API version: 0.55.3+1.19\
Modmenu version: 4.0.0
#### 1.18.2
Supported MC versions: [1.18.2]\
#### 1.18.2 mods
Forge version: 40.0.18\
Fabric version: 0.13.3\
Fabric API version: 0.48.0+1.18.2\
Modmenu version: 3.1.0
#### 1.18.1
Supported MC versions: [1.18.1, 1.18]\
#### 1.18.1 mods
Forge version: 39.1.2\
Fabric version: 0.13.3\
Fabric API version: 0.42.6+1.18\
Fabric API version: 0.46.6+1.18\
Modmenu version: 3.0.1
#### 1.17.1
Supported MC versions: [1.17.1, 1.17]\
Forge version: 37.1.1\
Fabric version: 0.13.2\
Fabric API version: 0.46.1+1.17\
Modmenu version: 2.0.14
#### 1.16.5
Supported MC versions: [1.16.5, 1.16.4]\
Forge version: 36.2.28\
Fabric vetsion: 0.13.2\
Fabric API version: 0.42.0+1.16\
Modmenu version: 1.16.22
<br><br>
Notes:\
This version has been confirmed to work in IDE and Retail Minecraft.\
(Retail running forge version 1.18.1-39.0.5 and fabric version 1.18-0.12.12 and 1.18.1-0.13.2)
#### Plugin and Library versions
Architectury version: 3.4-SNAPSHOT\
Architectury loom version: 0.12.0-SNAPSHOT\
Java Compiler plugin: Manifold Preprocessor
<br>
## Source Code Installation
See the Fabric Documentation online for more detailed instructions:\
https://fabricmc.net/wiki/tutorial:setup
### Prerequisites
* A Java Development Kit (JDK) for Java 17 (recommended) or newer. <br>
Visit https://www.oracle.com/java/technologies/downloads/ for installers.
* Git or someway to clone git projects. <br>
Visit https://git-scm.com/ for installers.
* A Java Development Kit (JDK) for Java 17 (recommended) or newer. Visit https://www.oracle.com/java/technologies/downloads/ for installers.
* Git or someway to clone git projects. Visit https://git-scm.com/ for installers.
* (Not required) Any Java IDE with plugins that support Manifold, for example Intellij IDEA.
**If using IntelliJ:**
1. Install the Manifold plugin
2. Open IDEA and import the build.gradle
3. Refresh the Gradle project in IDEA if required
0. Install Manifold plugin
1. open IDEA and import the build.gradle
2. 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`
**If using Ecplise: (Note that Eclispe currently 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
## Switching Versions
This branch support 2 built versions:
- 1.18.2
- 1.18.1 (which also runs on 1.18)
To switch between active versions, change `mcVer=1.?` in `gradle.properties` file.
To switch between active versions, change `mcVer=1.18.?` in `gradle.properties` file.
If running in an IDE, to ensure the IDE noticed the version change, run a gradle command to prompt gradle into updating the libs. (In IntellJ you will also need to do a gradle sync if it didn't happen automatically.)
>Note: There may be a `java.nio.file.FileSystemException` thrown when running the command after switching versions. To fix it, either restart your IDE (as your IDE is locking up a file) or use a tool like LockHunter to unlock the linked file(s). (Generally it is a lib file under `common\build\lib`, `forge\build\lib`, or `fabric\build\lib`). If anyone knows how to solve this issue please write a comment on this issue: https://gitlab.com/jeseibel/minecraft-lod-mod/-/issues/233
If running on IDE, to ensure IDE pickup the changed versions, you will need to run a gradle command again to allow gradle to update all the libs. (In IntellJ you will also need to do a gradle sync again if it didn't start it automatically.)
>Note: There may be a `java.nio.file.FileSystemException` thrown on running the command after switching versions. To fix it, either restart your IDE (as your IDE is locking up a file) or use tools like LockHunter to unlock the linked file. (Often a lib file under `common\build\lib` or `forge\build\lib` or `fabric\build\lib`). If anyone knows how to solve this issue please comment to this issue: https://gitlab.com/jeseibel/minecraft-lod-mod/-/issues/233
<br>
## Compiling
**From the File Explorer:**
1. Download and extract the zip of the project
**Using GUI**
1. Download the zip of the project and extract it
2. Download the core from https://gitlab.com/jeseibel/distant-horizons-core and extract into a folder called `core`
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`
3. Open a command line in the project folder
4. Run the command: `./gradlew assemble`
5. Then run command: `./gradlew mergeJars`
6. The compiled jar file will be in the folder `Merged`
**If in terminal:**
1. `git clone --recurse-submodules https://gitlab.com/jeseibel/minecraft-lod-mod.git`
1. `git clone -b 1.18.X --recurse-submodules https://gitlab.com/jeseibel/minecraft-lod-mod.git`
2. `cd minecraft-lod-mod`
3. `./gradlew assemble`
4. The compiled jar file will be in the folder `Merged`
4. `./gradlew mergeJars`
5. The compiled jar file will be in the folder `Merged`
>Note: You can add the arg: `-PmcVer=1.18.?` to tell gradle to build a selected MC version instead of having to manually modify the `gradle.properties` file.
>Note: You can add the arg: `-PmcVer=1.?` to tell gradle to build a selected MC version instead of having to manually modify the `gradle.properties` file.
<Br>
## Other commands
@@ -124,40 +101,19 @@ If running in an IDE, to ensure the IDE noticed the version change, run a gradle
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`\
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>
Source code uses Mojang mappings.
## Useful commands
Run the standalone jar: `./gradlew run`\
Build the standalone jar: `./gradlew core:build`\
Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build`\
Only build Forge: `./gradlew fabric:assemble` or `./gradlew forge:build`\
Build only Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build`\
Build only Forge: `./gradlew fabric:assemble` or `./gradlew forge:build`\
Run the Fabric client (for debugging): `./gradlew fabric:runClient`\
Run the Forge client (for debugging): `./gradlew forge:runClient`
To build all versions: `./buildAll` (all builds will end up in the `Merged` folder)
<br>
## Open Source Acknowledgements
XZ for Java (data compression)\
https://tukaani.org/xz/java.html
Forgix (To merge multiple mod versions into one jar) [_Used to be_ [_DHJarMerger_](https://github.com/Ran-helo/DHJarMerger)]\
https://github.com/PacifistMC/Forgix
Json & Toml for Java (config handling)\
https://github.com/TheElectronWill/night-config
SVG Salamander for SVG's\
https://github.com/blackears/svgSalamander
FlatLaf for theming (Tempory to test stuff)\
https://www.formdev.com/flatlaf/
DHJarMerger (To merge multiple mod versions into one jar)\
https://github.com/Ran-helo/DHJarMerger
+88 -323
View File
@@ -1,295 +1,91 @@
import io.github.ran.jarmerger.JarMergerPlugin
buildscript {
dependencies{
classpath files('plugins/DHJarMerger-1.0.jar')
}
}
plugins {
// Plugin to help in developing multi-loader mods
id "architectury-plugin" version "3.4-SNAPSHOT"
id "dev.architectury.loom" version "0.12.0-SNAPSHOT" apply false
// Plugin to handle dependencies
id 'com.github.johnrengelman.shadow' version '7.0.0' apply false
// Plugin to create merged jars
id "io.github.pacifistmc.forgix" version "1.2.6"
// Provides mc libraries to core
id 'org.spongepowered.gradle.vanilla' version '0.2.1-SNAPSHOT' apply false
id "dev.architectury.loom" version "0.10.0-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) {
ArrayList<String> redefineList = new ArrayList<String>()
for (int i=0; i<mcVers.size(); i++) {
String mcStr = mcVers.get(i).replace(".", "_")
if (mcIndex<i) {
redefineList.add("PRE_MC_"+mcStr)
}
if (mcIndex==i) {
redefineList.add("MC_"+mcStr)
}
if (mcIndex>=i) {
redefineList.add("POST_MC_"+mcStr)
}
}
// build the list of preprocessors to use
StringBuilder sb = new StringBuilder()
// 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")
sb.append("=\n")
}
// build the MC version preprocessors
for (String redefinedVersion : redefineList) {
sb.append(redefinedVersion)
sb.append("=\n")
}
new File(projectDir, "build.properties").text = sb.toString()
def writeBuildGradlePredefine() {
def excapedMCVersion = rootProject.minecraft_version.replace(".", "_")
new File(projectDir, "build.properties").text = "MC_VERSION_${excapedMCVersion}=\n"
}
// Sets up the variables for Manifold in the code
def loadProperties() {
def defaultMcVersion = "1.19.2"
// def defaultMcVersion = "1.19" // For now use 1.18.2 as default until 1.19 is done
def mcVersion = ""
def mcVers = mcVersions.split(",")
int mcIndex = -1
println "Avalible MC versions: ${mcVersions}"
if (project.hasProperty("mcVer")) {
mcVersion = mcVer
mcIndex = Arrays.asList(mcVers).indexOf(mcVer)
}
if (mcIndex == -1) {
println "No mcVer set or the set mcVer is invalid! Defaulting to ${defaultMcVersion}."
def defaultMcVersion = '1.18.2'
if (!project.hasProperty("mcVer")) {
println "No mcVer set! Defaulting to ${defaultMcVersion}."
println "Tip: Use -PmcVer='${defaultMcVersion}' in cmd arg to set mcVer."
mcVersion = defaultMcVersion
mcIndex = Arrays.asList(mcVers).indexOf(defaultMcVersion)
assert mcIndex != -1
}
def mcVersion = project.hasProperty("mcVer") ? mcVer : defaultMcVersion
println "Loading properties file at " + mcVersion + ".properties"
def props = new Properties()
props.load(new FileInputStream("$rootProject.rootDir/"+"$mcVersion"+".properties"))
props.each { prop ->
rootProject.ext.set(prop.key, prop.value)
// println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
}
writeBuildGradlePredefine(Arrays.asList(mcVers), mcIndex)
// Stuff for access wideners
def mcVersionToAcsessWidenerVersion = [
"1.16.5": "1_16",
"1.17.1": "1_17",
"1.18.1": "1_18",
"1.18.2": "1_18",
"1.19": "1_19",
"1.19.1": "1_19",
"1.19.2": "1_19"
]
// Use this as sometimes multiple versions use the same access wideners
rootProject.ext.set("accessWidenerVersion", mcVersionToAcsessWidenerVersion.get(mcVersion))
writeBuildGradlePredefine()
}
loadProperties()
// Sets up the accesswideners
def makeAccessWidener() {
def accessWidenerFile = project(":common").file("src/main/resources/lod.accesswidener")
if (accessWidenerFile.exists()) {
delete accessWidenerFile
}
copy {
from project(":common").file("src/main/resources/${rootProject.accessWidenerVersion}.lod.accesswidener")
into project(":common").file("src/main/resources/")
rename "${rootProject.accessWidenerVersion}.lod.accesswidener", "lod.accesswidener"
}
}
makeAccessWidener()
// Sets up the version string
rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm")
// Merged jar settings
forgix {
group = "com.seibel.lod"
mergedJarName = "DistantHorizons-${rootProject.versionStr}.jar"
forge {
jarLocation = "build/libs/DistantHorizons-${rootProject.versionStr}.jar"
}
fabric {
jarLocation = "build/libs/DistantHorizons-${rootProject.versionStr}.jar"
}
removeDuplicate "com.seibel.lod.api"
removeDuplicate "com.seibel.lod.core"
}
apply plugin: JarMergerPlugin
architectury {
minecraft = rootProject.minecraft_version
}
subprojects { p ->
// setup Architectury
if (p == project(":core") || p == project(":api")) {
apply plugin: "application"
apply plugin: "org.spongepowered.gradle.vanilla" // Provides minecraft libraries
apply plugin: "com.github.johnrengelman.shadow"
} else {
apply plugin: "com.github.johnrengelman.shadow"
apply plugin: "dev.architectury.loom"
loom {
silentMojangMappingsLicense()
}
apply plugin: "dev.architectury.loom"
loom {
silentMojangMappingsLicense()
}
// set up custom configurations (configurations are a way to handle dependencies)
configurations {
// extends the shadowJar configuration
common
shadowMe
// have implemented dependencies automatically embedded in the final jar
implementation.extendsFrom(shadowMe)
customModule
implementation.extendsFrom(customModule)
}
// Set up the minecraft non-dependency for core sub-projects
if (p == project(":core") || p == project(":api")) {
minecraft {
version("${rootProject.minecraft_version}")
}
// Set the standalone jar entrypoint
// (This will point to a non-existent class in all sub-projects except "Core")
application {
mainClass.set('com.seibel.lod.core.jar.JarMain')
}
implementation.extendsFrom shadowMe
}
dependencies {
//=====================//
// shared dependencies //
//=====================//
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
// The following line declares the mojmap mappings
mappings loom.officialMojangMappings()
//Manifold
annotationProcessor "systems.manifold:manifold-preprocessor:${rootProject.manifold_version}"
// Manifold
annotationProcessor("systems.manifold:manifold-preprocessor:${rootProject.manifold_version}")
// Toml
implementation("com.electronwill.night-config:toml:${rootProject.toml_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")
// Compression
shadowMe("org.tukaani:xz:1.9")
shadowMe("org.apache.commons:commons-compress:1.21")
// NightConfig (includes Toml & Json)
shadowMe("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
shadowMe("com.electronwill.night-config:json:${rootProject.nightconfig_version}")
// Theming
shadowMe("com.formdev:flatlaf:${rootProject.flatlaf_version}")
// SVG
shadowMe("com.formdev:flatlaf-extras:${rootProject.flatlaf_version}")
shadowMe("com.formdev:svgSalamander:${rootProject.svgSalamander_version}")
//==========================//
// conditional dependencies //
//==========================//
// The logic for buildForge can be made more succinct, but the readability goes way down.
def buildForge = true
if (gradle.startParameter.taskRequests.size() > 0) {
if (gradle.startParameter.taskRequests[0].args.size() > 0) {
if (gradle.startParameter.taskRequests[0].args[0].startsWith("fabric:")) {
buildForge = false
}
}
if (p != project(":forge")) {
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
// Do NOT use other classes from fabric loader unless working with fabric
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
}
// Minecraft dependent sub-projects
if (p == project(":common") || (buildForge && p == project(":forge")) || p == project(":fabric")) {
// Add Minecraft
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
// The following line declares the mojmap mappings & parchment mappings
mappings loom.layered() {
// Mojmap mappings
officialMojangMappings()
// Parchment mappings (it adds parameter mappings & javadoc)
parchment("org.parchmentmc.data:parchment-${rootProject.minecraft_version}:${rootProject.parchment_version}@zip")
}
}
// Add core
if (p != project(":api") && p != project(":core")) {
implementation(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"
}
}
// Add the api
if (p != project(":api")) {
implementation(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"
}
if (p != project(":core")) {
common(project(":core")) { transitive false }
shadowMe(project(":core")) { transitive false }
}
}
// Allows the jar to run standalone
jar {
manifest {
attributes 'Implementation-Title': rootProject.archives_base_name,
'Implementation-Version': rootProject.mod_version,
'Main-Class': 'com.seibel.lod.core.jar.JarMain' // When changing the main of the jar change this line
'Main-Class': 'com.seibel.lod.core.JarMain'
}
}
// 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()
// }
// }
// }
// Run mergeJars when running build
if (p != project(":api") && p != project(":api")) {
build.finalizedBy(mergeJars)
assemble.finalizedBy(mergeJars)
}
}
allprojects { p ->
@@ -303,18 +99,11 @@ allprojects { p ->
repositories {
mavenCentral()
// For parchment mappings
maven { url "https://maven.parchmentmc.org" }
// For Architectury API
maven { url "https://maven.architectury.dev" }
// used to download and compile dependencies from git repos
maven { url 'https://jitpack.io' }
// For Manifold Preprocessor
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
// For Manifold Preprocessor
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
// Required for importing Modrinth mods
maven {
@@ -333,15 +122,6 @@ allprojects { p ->
}
}
// Required for ModMenu
maven { url "https://maven.terraformersmc.com/" }
// Required for Mixins & VanillaGradle
maven { url "https://repo.spongepowered.org/maven/" }
// Required for canvas
maven { url "https://maven.vram.io/" }
// These 2 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
flatDir {
dirs "${rootDir}/mods/fabric"
@@ -358,49 +138,22 @@ allprojects { p ->
}
// Only uncomment this when testing stuff with lwjgl in the core jar
// if (p == project(":core")) {
// dependencies {
// project.ext.lwjglNatives = "natives-linux"
//
// implementation platform("org.lwjgl:lwjgl-bom:3.3.0")
//
// 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:1.10.2"
// }
// }
// Put stuff from gradle.properties into the mod info
processResources {
def resourceTargets = ["fabric.mod.json", "META-INF/mods.toml"] // Location of where to put
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
def replaceProperties = [
version : mod_version,
mod_name : mod_name,
authors : mod_authors,
description : mod_description,
homepage : mod_homepage,
source : mod_source,
issues : mod_issues,
minecraft_version : minecraft_version,
compatible_minecraft_versions: compatible_minecraft_versions,
java_version : java_version
]
// 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
//TODO: Make Forge loader version also be relaced with non hardcoded value instead of "[36,42)"
version: mod_version,
mod_name: mod_name,
authors: mod_authors,
description: mod_description,
homepage: mod_homepage,
source: mod_source,
issues: mod_issues,
minecraft_version: minecraft_version,
java_version: java_version
] // 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
//TODO: Make Forge loader version also be relaced with non hardcoded value instead of "[36,41)"
inputs.properties replaceProperties
replaceProperties.put 'project', project
@@ -421,40 +174,52 @@ allprojects { p ->
}
}
task copyCoreResources(type: Copy) {
from fileTree(project(":core").file("src/main/resources"))
into p.file("build/resources/main")
}
tasks.withType(JavaCompile) {
// Add Manifold Preprocessor
// def excapedMCVersion = rootProject.minecraft_version.replace(".", "_")
// options.compilerArgs += ['-Xplugin:Manifold', "-AMC_VERSION_${excapedMCVersion}"]
//
//options.compilerArgs += ['-deprecation']
//options.compilerArgs += ['-verbose']
//options.compilerArgs += ['-Xlint:unchecked']
//options.compilerArgs += ['-Xdiags:verbose']
//options.compilerArgs += ['-Xprint']
//options.compilerArgs += ['-XprintProcessorInfo']
//options.compilerArgs += ['-XprintRounds']
// println options.compilerArgs
if (p != project(":core")) {
options.release = rootProject.java_version as Integer
options.compilerArgs += ['-Xplugin:Manifold']
} else {
// options.release = 8; // Core should use Java 8 no matter what
// No it shouldn't cause it fails to find minecraft if it uses Java 8
options.release = rootProject.java_version as Integer
}
options.encoding = "UTF-8"
}
java {
withSourcesJar()
}
// Disable running common
if (p == project(":common")) {
if (p == project(":core") || p == project(":common")) {
runClient.enabled = false
runServer.enabled = false
}
}
// Delete the merged folder when running clean
task cleanMergedJars() {
def mergedFolder = file("Merged")
if (mergedFolder.exists()) {
delete(mergedFolder)
// this is necessary for running the fabric build
if (p == project(":common")) {
println "Coping [common/src/main/resources/lod.accesswidner] to [fabric/build/resources/main]."
copy {
from "$rootProject.rootDir/common/src/main/resources"
into "$rootProject.rootDir/fabric/build/resources/main"
include "*.accesswidener"
}
}
}
// add cleanMergedJars to the end of the "clean" task
tasks["clean"].finalizedBy(cleanMergedJars)
// this deletes the merged folder so we don't carry over
// the previous merges to each new build job in the CI/CD pipeline
task deleteMerged(type: Delete) {
delete files("./Merged")
}
-13
View File
@@ -1,13 +0,0 @@
#!/usr/bin/env sh
buildVersion()
{
./gradlew clean -PmcVer=$1 --no-daemon
./gradlew build -PmcVer=$1 --no-daemon
}
buildVersion 1.19
buildVersion 1.18.2
buildVersion 1.18.1
buildVersion 1.17.1
buildVersion 1.16.5
-16
View File
@@ -1,16 +0,0 @@
@echo off
SETLOCAL
CALL :buildVersion "1.19"
CALL :buildVersion "1.18.2"
CALL :buildVersion "1.18.1"
CALL :buildVersion "1.17.1"
CALL :buildVersion "1.16.5"
EXIT /B %ERRORLEVEL%
:buildVersion
@echo on
call ./gradlew.bat clean -PmcVer="%~1" --no-daemon
call ./gradlew.bat build -PmcVer="%~1" --no-daemon
@echo off
EXIT /B 0
+10 -14
View File
@@ -1,20 +1,16 @@
architectury {
common(rootProject.enabled_platforms.split(","))
}
loom {
accessWidenerPath = file("src/main/resources/lod.accesswidener")
accessWidenerPath.set(file("src/main/resources/lod.accesswidener"))
}
dependencies {
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
// Do NOT use other classes from fabric loader
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
architectury {
common()
}
if (minecraft_version == "1.16.5") {
modApi("me.shedaniel:architectury:${rootProject.architectury_version}")
} else {
modApi("dev.architectury:architectury:${rootProject.architectury_version}")
afterEvaluate {
tasks {
remapJar {
remapAccessWidener.set(false)
}
}
}
@@ -30,4 +26,4 @@ publishing {
repositories {
// Add repositories to publish to here.
}
}
}
@@ -0,0 +1,485 @@
/*
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.common;
import com.seibel.lod.core.config.*;
import com.seibel.lod.core.enums.config.*;
import com.seibel.lod.core.enums.rendering.*;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IAdvanced.*;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IGraphics.*;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IGraphics.IFogQuality.IAdvancedFog;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IGraphics.IFogQuality.IAdvancedFog.IHeightFog;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IMultiplayer;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IWorldGenerator;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IAdvanced;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IAdvanced.IDebugging.*;
/**
* This handles any configuration the user has access to.
* @author coolGi2007
* @version 12-12-2021
*/
public class Config
//public class Config extends TinyConfig
{
// CONFIG STRUCTURE
// -> Client
// |
// |-> Graphics
// | |-> Quality
// | |-> FogQuality
// | |-> AdvancedGraphics
// |
// |-> World Generation
// |
// |-> Advanced
// |-> Threads
// |-> Buffers
// |-> Debugging
// Since the original config system uses forge stuff, that means we have to rewrite the whole config system
@ConfigAnnotations.ScreenEntry
public static Client client;
@ConfigAnnotations.FileComment
public static String _optionsButton = ILodConfigWrapperSingleton.IClient.OPTIONS_BUTTON_DESC;
// I know this option should be in Client
// This is a hacky method to not show the button in the options screen but show it in the mod menu
// Tough it is in client in the wrapper singleton
@ConfigAnnotations.Entry
public static boolean optionsButton = true;
public static class Client
{
@ConfigAnnotations.ScreenEntry
public static Graphics graphics;
@ConfigAnnotations.ScreenEntry
public static WorldGenerator worldGenerator;
@ConfigAnnotations.ScreenEntry
public static Multiplayer multiplayer;
@ConfigAnnotations.ScreenEntry
public static Advanced advanced;
public static class Graphics
{
@ConfigAnnotations.ScreenEntry
public static Quality quality;
@ConfigAnnotations.ScreenEntry
public static FogQuality fogQuality;
@ConfigAnnotations.ScreenEntry
public static AdvancedGraphics advancedGraphics;
public static class Quality
{
@ConfigAnnotations.FileComment
public static String _drawResolution = IQuality.DRAW_RESOLUTION_DESC;
@ConfigAnnotations.Entry
public static HorizontalResolution drawResolution = IQuality.DRAW_RESOLUTION_DEFAULT;
@ConfigAnnotations.FileComment
public static String _lodChunkRenderDistance = IQuality.LOD_CHUNK_RENDER_DISTANCE_DESC;
@ConfigAnnotations.Entry(minValue = 16, maxValue = 2048)
public static int lodChunkRenderDistance = IQuality.LOD_CHUNK_RENDER_DISTANCE_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _verticalQuality = IQuality.VERTICAL_QUALITY_DESC;
@ConfigAnnotations.Entry
public static VerticalQuality verticalQuality = IQuality.VERTICAL_QUALITY_DEFAULT;
@ConfigAnnotations.FileComment
public static String _horizontalScale = IQuality.HORIZONTAL_SCALE_DESC;
@ConfigAnnotations.Entry(minValue = 2, maxValue = 32)
public static int horizontalScale = IQuality.HORIZONTAL_SCALE_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _horizontalQuality = IQuality.HORIZONTAL_SCALE_DESC;
@ConfigAnnotations.Entry
public static HorizontalQuality horizontalQuality = IQuality.HORIZONTAL_QUALITY_DEFAULT;
@ConfigAnnotations.FileComment
public static String _dropoffQuality = IQuality.DROPOFF_QUALITY_DESC;
@ConfigAnnotations.Entry
public static DropoffQuality dropoffQuality = IQuality.DROPOFF_QUALITY_DEFAULT;
@ConfigAnnotations.FileComment
public static String _lodBiomeBlending = IQuality.LOD_BIOME_BLENDING_DESC;
@ConfigAnnotations.Entry(minValue = 0, maxValue = 7)
public static int lodBiomeBlending = IQuality.LOD_BIOME_BLENDING_MIN_DEFAULT_MAX.defaultValue;
}
public static class FogQuality
{
@ConfigAnnotations.FileComment
public static String _fogDistance = IFogQuality.FOG_DISTANCE_DESC;
@ConfigAnnotations.Entry
public static FogDistance fogDistance = IFogQuality.FOG_DISTANCE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _fogDrawMode = IFogQuality.FOG_DRAW_MODE_DESC;
@ConfigAnnotations.Entry
public static FogDrawMode fogDrawMode = IFogQuality.FOG_DRAW_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _fogColorMode = IFogQuality.FOG_COLOR_MODE_DESC;
@ConfigAnnotations.Entry
public static FogColorMode fogColorMode = IFogQuality.FOG_COLOR_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _disableVanillaFog = IFogQuality.DISABLE_VANILLA_FOG_DESC;
@ConfigAnnotations.Entry
public static boolean disableVanillaFog = IFogQuality.DISABLE_VANILLA_FOG_DEFAULT;
@ConfigAnnotations.ScreenEntry
public static AdvancedFog advancedFog;
public static class AdvancedFog {
static final double SQRT2 = 1.4142135623730951;
@ConfigAnnotations.FileComment
public static String _farFogStart = IAdvancedFog.FAR_FOG_START_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = SQRT2)
public static double farFogStart = IAdvancedFog.FAR_FOG_START_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _farFogEnd = IAdvancedFog.FAR_FOG_END_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = SQRT2)
public static double farFogEnd = IAdvancedFog.FAR_FOG_END_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _farFogMin = IAdvancedFog.FAR_FOG_MIN_DESC;
@ConfigAnnotations.Entry(minValue = -5.0, maxValue = SQRT2)
public static double farFogMin = IAdvancedFog.FAR_FOG_MIN_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _farFogMax = IAdvancedFog.FAR_FOG_MAX_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = 5.0)
public static double farFogMax = IAdvancedFog.FAR_FOG_MAX_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _farFogType = IAdvancedFog.FAR_FOG_TYPE_DESC;
@ConfigAnnotations.Entry
public static FogSetting.FogType farFogType = IAdvancedFog.FAR_FOG_TYPE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _farFogDensity = IAdvancedFog.FAR_FOG_DENSITY_DESC;
@ConfigAnnotations.Entry(minValue = 0.01, maxValue = 50.0)
public static double farFogDensity = IAdvancedFog.FAR_FOG_DENSITY_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.ScreenEntry
public static HeightFog heightFog;
public static class HeightFog {
@ConfigAnnotations.FileComment
public static String _heightFogMixMode = IHeightFog.HEIGHT_FOG_MIX_MODE_DESC;
@ConfigAnnotations.Entry
public static HeightFogMixMode heightFogMixMode = IHeightFog.HEIGHT_FOG_MIX_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _heightFogMode = IHeightFog.HEIGHT_FOG_MODE_DESC;
@ConfigAnnotations.Entry
public static HeightFogMode heightFogMode = IHeightFog.HEIGHT_FOG_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _heightFogHeight = IHeightFog.HEIGHT_FOG_HEIGHT_DESC;
@ConfigAnnotations.Entry(minValue = -4096.0, maxValue = 4096.0)
public static double heightFogHeight = IHeightFog.HEIGHT_FOG_HEIGHT_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _heightFogStart = IHeightFog.HEIGHT_FOG_START_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = SQRT2)
public static double heightFogStart = IHeightFog.HEIGHT_FOG_START_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _heightFogEnd = IHeightFog.HEIGHT_FOG_END_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = SQRT2)
public static double heightFogEnd = IHeightFog.HEIGHT_FOG_END_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _heightFogMin = IHeightFog.HEIGHT_FOG_MIN_DESC;
@ConfigAnnotations.Entry(minValue = -5.0, maxValue = SQRT2)
public static double heightFogMin = IHeightFog.HEIGHT_FOG_MIN_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _heightFogMax = IHeightFog.HEIGHT_FOG_MAX_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = 5.0)
public static double heightFogMax = IHeightFog.HEIGHT_FOG_MAX_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _heightFogType = IHeightFog.HEIGHT_FOG_TYPE_DESC;
@ConfigAnnotations.Entry
public static FogSetting.FogType heightFogType = IHeightFog.HEIGHT_FOG_TYPE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _heightFogDensity = IHeightFog.HEIGHT_FOG_DENSITY_DESC;
@ConfigAnnotations.Entry(minValue = 0.01, maxValue = 50.0)
public static double heightFogDensity = IHeightFog.HEIGHT_FOG_DENSITY_MIN_DEFAULT_MAX.defaultValue;
}
}
}
public static class AdvancedGraphics
{
@ConfigAnnotations.FileComment
public static String _disableDirectionalCulling = IAdvancedGraphics.DISABLE_DIRECTIONAL_CULLING_DESC;
@ConfigAnnotations.Entry
public static boolean disableDirectionalCulling = IAdvancedGraphics.DISABLE_DIRECTIONAL_CULLING_DEFAULT;
@ConfigAnnotations.FileComment
public static String _vanillaOverdraw = IAdvancedGraphics.VANILLA_OVERDRAW_DESC;
@ConfigAnnotations.Entry
public static VanillaOverdraw vanillaOverdraw = IAdvancedGraphics.VANILLA_OVERDRAW_DEFAULT;
@ConfigAnnotations.FileComment
public static String _overdrawOffset = IAdvancedGraphics.OVERDRAW_OFFSET_DESC;
@ConfigAnnotations.Entry(minValue = -16, maxValue = 16)
public static int overdrawOffset = IAdvancedGraphics.OVERDRAW_OFFSET_MIN_DEFAULT_MAX.defaultValue;
@ConfigAnnotations.FileComment
public static String _useExtendedNearClipPlane = IAdvancedGraphics.USE_EXTENDED_NEAR_CLIP_PLANE_DESC;
@ConfigAnnotations.Entry
public static boolean useExtendedNearClipPlane = IAdvancedGraphics.USE_EXTENDED_NEAR_CLIP_PLANE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _brightnessMultiplier = IAdvancedGraphics.BRIGHTNESS_MULTIPLIER_DESC;
@ConfigAnnotations.Entry
public static double brightnessMultiplier = IAdvancedGraphics.BRIGHTNESS_MULTIPLIER_DEFAULT;
@ConfigAnnotations.FileComment
public static String _saturationMultiplier = IAdvancedGraphics.SATURATION_MULTIPLIER_DESC;
@ConfigAnnotations.Entry
public static double saturationMultiplier = IAdvancedGraphics.SATURATION_MULTIPLIER_DEFAULT;
@ConfigAnnotations.FileComment
public static String _enableCaveCulling = IAdvancedGraphics.ENABLE_CAVE_CULLING_DESC;
@ConfigAnnotations.Entry
public static boolean enableCaveCulling = IAdvancedGraphics.ENABLE_CAVE_CULLING_DEFAULT;
@ConfigAnnotations.FileComment
public static String _caveCullingHeight = IAdvancedGraphics.CAVE_CULLING_HEIGHT_DESC;
@ConfigAnnotations.Entry(minValue = -4096, maxValue = 4096)
public static int caveCullingHeight = IAdvancedGraphics.CAVE_CULLING_HEIGHT_MIN_DEFAULT_MAX.defaultValue;
/*
@ConfigAnnotations.FileComment
public static String _backsideCullingRange = IAdvancedGraphics.VANILLA_CULLING_RANGE_DESC;
@ConfigAnnotations.Entry(minValue = 0, maxValue = 512)
public static int backsideCullingRange = IAdvancedGraphics.VANILLA_CULLING_RANGE_MIN_DEFAULT_MAX.defaultValue;
*/
}
}
public static class WorldGenerator
{
@ConfigAnnotations.FileComment
public static String _enableDistantGeneration = IWorldGenerator.ENABLE_DISTANT_GENERATION_DESC;
@ConfigAnnotations.Entry
public static boolean enableDistantGeneration = IWorldGenerator.ENABLE_DISTANT_GENERATION_DEFAULT;
// @ConfigAnnotations.FileComment
// public static String _distanceGenerationMode = IWorldGenerator.getDistanceGenerationModeDesc();
@ConfigAnnotations.Entry
public static DistanceGenerationMode distanceGenerationMode = IWorldGenerator.DISTANCE_GENERATION_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _lightGenerationMode = IWorldGenerator.LIGHT_GENERATION_MODE_DESC;
@ConfigAnnotations.Entry
public static LightGenerationMode lightGenerationMode = IWorldGenerator.LIGHT_GENERATION_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _generationPriority = IWorldGenerator.GENERATION_PRIORITY_DESC;
@ConfigAnnotations.Entry
public static GenerationPriority generationPriority = IWorldGenerator.GENERATION_PRIORITY_DEFAULT;
/*
@ConfigAnnotations.FileComment
public static String _allowUnstableFeatureGeneration = IWorldGenerator.ALLOW_UNSTABLE_FEATURE_GENERATION_DESC;
// FIXME: Temperary override. In 1.18, the newer Unstable gnerator is more usable
@ConfigAnnotations.Entry
public static boolean allowUnstableFeatureGeneration = true;//IWorldGenerator.ALLOW_UNSTABLE_FEATURE_GENERATION_DEFAULT;
*/
@ConfigAnnotations.FileComment
public static String _blocksToAvoid = IWorldGenerator.BLOCKS_TO_AVOID_DESC;
@ConfigAnnotations.Entry
public static BlocksToAvoid blocksToAvoid = IWorldGenerator.BLOCKS_TO_AVOID_DEFAULT;
}
public static class Multiplayer
{
@ConfigAnnotations.FileComment
public static String _serverFolderNameMode = IMultiplayer.SERVER_FOLDER_NAME_MODE_DESC;
@ConfigAnnotations.Entry
public static ServerFolderNameMode serverFolderNameMode = IMultiplayer.SERVER_FOLDER_NAME_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _multiDimensionRequiredSimilarity = IMultiplayer.MULTI_DIMENSION_REQUIRED_SIMILARITY_DESC;
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = 1.0)
public static double multiDimensionRequiredSimilarity = IMultiplayer.MULTI_DIMENSION_REQUIRED_SIMILARITY_MIN_DEFAULT_MAX.defaultValue;
}
public static class Advanced
{
@ConfigAnnotations.ScreenEntry
public static Threading threading;
@ConfigAnnotations.ScreenEntry
public static Debugging debugging;
@ConfigAnnotations.ScreenEntry
public static Buffers buffers;
@ConfigAnnotations.FileComment
public static String _lodOnlyMode = IAdvanced.LOD_ONLY_MODE_DESC;
@ConfigAnnotations.Entry
public static boolean lodOnlyMode = IAdvanced.LOD_ONLY_MODE_DEFAULT;
public static class Threading
{
@ConfigAnnotations.FileComment
public static String _numberOfWorldGenerationThreads = IThreading.NUMBER_OF_WORLD_GENERATION_THREADS_DESC;
@ConfigAnnotations.Entry(minValue = 1, maxValue = 50)
public static int numberOfWorldGenerationThreads = IThreading.NUMBER_OF_WORLD_GENERATION_THREADS_DEFAULT.defaultValue;
@ConfigAnnotations.FileComment
public static String _numberOfBufferBuilderThreads = IThreading.NUMBER_OF_BUFFER_BUILDER_THREADS_DESC;
@ConfigAnnotations.Entry(minValue = 1, maxValue = 50)
public static int numberOfBufferBuilderThreads = IThreading.NUMBER_OF_BUFFER_BUILDER_THREADS_MIN_DEFAULT_MAX.defaultValue;
}
public static class Debugging
{
@ConfigAnnotations.FileComment
public static String _rendererType = IDebugging.RENDERER_TYPE_DESC;
@ConfigAnnotations.Entry
public static RendererType rendererType = IDebugging.RENDERER_TYPE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _debugMode = IDebugging.DEBUG_MODE_DESC;
@ConfigAnnotations.Entry
public static DebugMode debugMode = IDebugging.DEBUG_MODE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _enableDebugKeybindings = IDebugging.DEBUG_KEYBINDINGS_ENABLED_DESC;
@ConfigAnnotations.Entry
public static boolean enableDebugKeybindings = IDebugging.DEBUG_KEYBINDINGS_ENABLED_DEFAULT;
@ConfigAnnotations.ScreenEntry
public static DebugSwitch debugSwitch;
public static class DebugSwitch {
/* The logging switches available:
* WorldGenEvent
* WorldGenPerformance
* WorldGenLoadEvent
* LodBuilderEvent
* RendererBufferEvent
* RendererGLEvent
* FileReadWriteEvent
* FileSubDimEvent
* NetworkEvent //NOT IMPL YET
*/
@ConfigAnnotations.FileComment
public static String _logWorldGenEvent = IDebugSwitch.LOG_WORLDGEN_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logWorldGenEvent = IDebugSwitch.LOG_WORLDGEN_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logWorldGenPerformance = IDebugSwitch.LOG_WORLDGEN_PERFORMANCE_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logWorldGenPerformance = IDebugSwitch.LOG_WORLDGEN_PERFORMANCE_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logWorldGenLoadEvent = IDebugSwitch.LOG_WORLDGEN_LOAD_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logWorldGenLoadEvent = IDebugSwitch.LOG_WORLDGEN_LOAD_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logLodBuilderEvent = IDebugSwitch.LOG_LODBUILDER_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logLodBuilderEvent = IDebugSwitch.LOG_LODBUILDER_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logRendererBufferEvent = IDebugSwitch.LOG_RENDERER_BUFFER_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logRendererBufferEvent = IDebugSwitch.LOG_RENDERER_BUFFER_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logRendererGLEvent = IDebugSwitch.LOG_RENDERER_GL_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logRendererGLEvent = IDebugSwitch.LOG_RENDERER_GL_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logFileReadWriteEvent = IDebugSwitch.LOG_FILE_READWRITE_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logFileReadWriteEvent = IDebugSwitch.LOG_FILE_READWRITE_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logFileSubDimEvent = IDebugSwitch.LOG_FILE_SUB_DIM_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logFileSubDimEvent = IDebugSwitch.LOG_FILE_SUB_DIM_EVENT_DEFAULT;
@ConfigAnnotations.FileComment
public static String _logNetworkEvent = IDebugSwitch.LOG_NETWORK_EVENT_DESC;
@ConfigAnnotations.Entry
public static LoggerMode logNetworkEvent = IDebugSwitch.LOG_NETWORK_EVENT_DEFAULT;
}
}
public static class Buffers
{
@ConfigAnnotations.FileComment
public static String _gpuUploadMethod = IBuffers.GPU_UPLOAD_METHOD_DESC;
@ConfigAnnotations.Entry
public static GpuUploadMethod gpuUploadMethod = IBuffers.GPU_UPLOAD_METHOD_DEFAULT;
@ConfigAnnotations.FileComment
public static String _gpuUploadPerMegabyteInMilliseconds = IBuffers.GPU_UPLOAD_PER_MEGABYTE_IN_MILLISECONDS_DESC;
@ConfigAnnotations.Entry(minValue = 0, maxValue = 50)
public static int gpuUploadPerMegabyteInMilliseconds = IBuffers.GPU_UPLOAD_PER_MEGABYTE_IN_MILLISECONDS_DEFAULT.defaultValue;
@ConfigAnnotations.FileComment
public static String _rebuildTimes = IBuffers.REBUILD_TIMES_DESC;
@ConfigAnnotations.Entry
public static BufferRebuildTimes rebuildTimes = IBuffers.REBUILD_TIMES_DEFAULT;
}
}
}
}
@@ -1,30 +1,9 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common;
import com.seibel.lod.common.forge.LodForgeMethodCaller;
import com.seibel.lod.common.networking.NetworkInterface;
import com.seibel.lod.common.wrappers.DependencySetup;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.api.internal.SharedApi;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.config.ConfigBase;
import com.seibel.lod.common.wrappers.config.ConfigGui;
/**
* This is the common main class
@@ -32,23 +11,29 @@ import com.seibel.lod.core.config.ConfigBase;
*/
public class LodCommonMain {
public static boolean forge = false;
public static boolean serverSided;
public static LodForgeMethodCaller forgeMethodCaller;
public static void startup(LodForgeMethodCaller caller) {
public static NetworkInterface networkInterface;
public static void startup(LodForgeMethodCaller caller, boolean serverSided, NetworkInterface networkInterface) {
LodCommonMain.serverSided = serverSided;
if (caller != null) {
LodCommonMain.forge = true;
forgeMethodCaller = caller;
}
DependencySetup.createSharedBindings();
SharedApi.init();
// if (!serverSided) {
// new NetworkReceiver().register_Client();
// } else {
// new NetworkReceiver().register_Server();
// }
DependencySetup.createInitialBindings();
LodCommonMain.networkInterface = networkInterface;
if (!serverSided) {
networkInterface.register_Client();
} else {
networkInterface.register_Server();
}
}
public static void initConfig() {
ConfigBase.INSTANCE = new ConfigBase(ModInfo.ID, ModInfo.NAME, Config.class,1);
ConfigGui.init(Config.class);
}
}
@@ -1,32 +1,8 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.forge;
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.core.Direction;
#if POST_MC_1_19
import net.minecraft.util.RandomSource;
#endif
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
@@ -39,11 +15,5 @@ import java.util.Random;
* @author Ran
*/
public interface LodForgeMethodCaller {
#if PRE_MC_1_19
List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, Random random); // FIXME: For 1.19
#else
List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, RandomSource random); // FIXME: For 1.19
#endif
int colorResolverGetColor(ColorResolver resolver, Biome biome, double x, double z);
List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, Random random);
}
@@ -1,27 +1,11 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.networking;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Player;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
/**
* This is packet handler for our mod
@@ -29,15 +13,18 @@ import net.minecraft.world.entity.player.Player;
*
* @author Ran
*/
// TODO: Server sided stuff here
public class NetworkHandler {
public static void receivePacketClient(Minecraft client, FriendlyByteBuf buf, Player player) {
// This just exists here for testing purposes, it'll be removed in the future
System.out.println("Received int " + buf.readInt());
// If you need the response sender then tell me
// I'll add extra code to get the response sender
public static void receivePacketClient(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf) {
// TODO: Server sided stuff here
// You can make client execute something by using client.execute(Runnable)
// In the fabric docs it says that client.execute is ran on the render thread?
}
public static void receivePacketServer(FriendlyByteBuf buf, Player player) {
// If you need the response sender then tell me
// I'll add extra code to get the response sender
public static void receivePacketServer(MinecraftServer server, ServerPlayer client, ServerGamePacketListenerImpl handler, FriendlyByteBuf buf) {
// TODO: Server sided stuff here
}
}
@@ -0,0 +1,9 @@
package com.seibel.lod.common.networking;
/**
* @author Ran
*/
public interface NetworkInterface {
void register_Client();
void register_Server();
}
@@ -1,57 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.networking;
#if MC_1_16_5
import me.shedaniel.architectury.networking.NetworkManager;
#else
import dev.architectury.networking.NetworkManager;
#endif
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
/**
* @author Ran
*/
// Comment: What does the 'server' side mean? Dedicated server? Or does it include the internal server?
// (I removed the hookup that calls the register method, since I'm not sure what it is doing yet)
public class NetworkReceiver {
public void register_Client() {
NetworkManager.registerReceiver(NetworkManager.serverToClient(), Networking.RESOURCE_LOCATION, new ClientReceiver());
}
public void register_Server() {
NetworkManager.registerReceiver(NetworkManager.clientToServer(), Networking.RESOURCE_LOCATION, new ServerReceiver());
}
static class ServerReceiver implements NetworkManager.NetworkReceiver {
@Override
public void receive(FriendlyByteBuf buf, NetworkManager.PacketContext context) {
com.seibel.lod.common.networking.NetworkHandler.receivePacketServer(buf, context.getPlayer());
}
}
static class ClientReceiver implements NetworkManager.NetworkReceiver {
@Override
public void receive(FriendlyByteBuf buf, NetworkManager.PacketContext context) {
com.seibel.lod.common.networking.NetworkHandler.receivePacketClient(Minecraft.getInstance(), buf, context.getPlayer());
}
}
}
@@ -1,30 +1,6 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.networking;
import com.seibel.lod.core.ModInfo;
#if MC_1_16_5
import me.shedaniel.architectury.networking.NetworkManager;
#else
import dev.architectury.networking.NetworkManager;
#endif
import io.netty.buffer.Unpooled;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
@@ -41,7 +17,7 @@ import java.util.Objects;
* @author Ran
*/
public class Networking {
public static final ResourceLocation RESOURCE_LOCATION = new ResourceLocation("lod", "data");
public static final ResourceLocation resourceLocation_meow = new ResourceLocation("lod", "meow");
public static FriendlyByteBuf createNew() {
// TODO: Probably replace the Unpooled.buffer()
@@ -50,6 +26,11 @@ public class Networking {
return buf;
}
/*
* All code below is from the fabric api and might have been modified to work with Distant Horizons
* Which is licensed under the Apache License 2.0
*/
/**
* Sends a packet to a player.
*
@@ -57,7 +38,11 @@ public class Networking {
* @param buf the payload of the packet.
*/
public static void send(ServerPlayer player, FriendlyByteBuf buf) {
NetworkManager.sendToPlayer(player, RESOURCE_LOCATION, buf);
Objects.requireNonNull(player, "Server player entity cannot be null");
Objects.requireNonNull(resourceLocation_meow, "Channel name cannot be null");
Objects.requireNonNull(buf, "Packet byte buf cannot be null");
player.connection.send(createS2CPacket(resourceLocation_meow, buf));
}
/**
@@ -67,7 +52,49 @@ public class Networking {
* @throws IllegalStateException if the client is not connected to a server
*/
public static void send(FriendlyByteBuf buf) throws IllegalStateException {
NetworkManager.sendToServer(RESOURCE_LOCATION, buf);
// You cant send without a client player, so this is fine
if (Minecraft.getInstance().getConnection() != null) {
Minecraft.getInstance().getConnection().send(createC2SPacket(resourceLocation_meow, buf));
return;
}
throw new IllegalStateException("Cannot send packets when not in game!");
}
/**
* Creates a packet which may be sent to the connected client.
*
* @param channelName the channel name
* @param buf the packet byte buf which represents the payload of the packet
* @return a new packet
*/
public static Packet<?> createS2CPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
Objects.requireNonNull(channelName, "Channel cannot be null");
Objects.requireNonNull(buf, "Buf cannot be null");
return createPlayS2CPacket(channelName, buf);
}
public static Packet<?> createPlayS2CPacket(ResourceLocation channel, FriendlyByteBuf buf) {
return new ClientboundCustomPayloadPacket(channel, buf);
}
/**
* Creates a packet which may be sent to a the connected server.
*
* @param channelName the channel name
* @param buf the packet byte buf which represents the payload of the packet
* @return a new packet
*/
public static Packet<?> createC2SPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
Objects.requireNonNull(channelName, "Channel name cannot be null");
Objects.requireNonNull(buf, "Buf cannot be null");
return createPlayC2SPacket(channelName, buf);
}
public static Packet<?> createPlayC2SPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
return new ServerboundCustomPayloadPacket(channelName, buf);
}
}
@@ -1,39 +1,15 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers;
import com.seibel.lod.common.wrappers.gui.LangWrapper;
import com.seibel.lod.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
import com.seibel.lod.core.wrapperInterfaces.config.ILangWrapper;
import com.seibel.lod.common.LodCommonMain;
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
import com.seibel.lod.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.lod.core.IReflectionHandler;
import com.seibel.lod.core.ReflectionHandler;
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.handlers.IReflectionHandler;
import com.seibel.lod.core.handlers.ReflectionHandler;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.config.LodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
/**
* Binds all necessary dependencies, so we
@@ -46,25 +22,17 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
* @version 12-1-2021
*/
public class DependencySetup {
public static void createSharedBindings()
public static void createInitialBindings()
{
SingletonInjector.INSTANCE.bind(ILodConfigWrapperSingleton.class, LodConfigWrapperSingleton.INSTANCE); // TODO: Remove
SingletonInjector.INSTANCE.bind(ILangWrapper.class, LangWrapper.INSTANCE);
SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE);
SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
SingletonHandler.bind(IVersionConstants.class, VersionConstants.INSTANCE);
if (!LodCommonMain.serverSided)
{
SingletonHandler.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE);
SingletonHandler.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
SingletonHandler.bind(IReflectionHandler.class, ReflectionHandler.createSingleton(MinecraftClientWrapper.INSTANCE.getOptions().getClass().getDeclaredFields(), MinecraftClientWrapper.INSTANCE.getOptions()));
}
SingletonHandler.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
DependencySetupDoneCheck.isDone = true;
}
//@Environment(EnvType.SERVER)
public static void createServerBindings() {
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftDedicatedServerWrapper.INSTANCE);
}
//@Environment(EnvType.CLIENT)
public static void createClientBindings() {
SingletonInjector.INSTANCE.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE);
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftClientWrapper.INSTANCE);
SingletonInjector.INSTANCE.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
SingletonInjector.INSTANCE.bind(IReflectionHandler.class, ReflectionHandler.INSTANCE);
}
}
@@ -1,22 +1,3 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers;
import java.util.function.Supplier;
@@ -1,37 +1,34 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
* 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
* it under the terms of the GNU 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.
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.common.wrappers;
import java.nio.FloatBuffer;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import com.mojang.math.Matrix4f;
import com.seibel.lod.core.enums.ELodDirection;
import com.seibel.lod.core.pos.DhBlockPos;
import com.seibel.lod.core.pos.DhChunkPos;
import com.seibel.lod.core.util.math.Mat4f;
import com.seibel.lod.common.wrappers.block.BlockPosWrapper;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.objects.math.Mat4f;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.ChunkPos;
/**
* This class converts to and from Minecraft objects (Ex: Matrix4f)
@@ -54,60 +51,29 @@ public class McObjectConverter
static final Direction[] directions;
static final ELodDirection[] lodDirections;
static final LodDirection[] lodDirections;
static {
ELodDirection[] lodDirs = ELodDirection.values();
LodDirection[] lodDirs = LodDirection.values();
directions = new Direction[lodDirs.length];
lodDirections = new ELodDirection[lodDirs.length];
for (ELodDirection lodDir : lodDirs) {
Direction dir = switch (lodDir.name().toUpperCase()) {
case "DOWN" -> Direction.DOWN;
case "UP" -> Direction.UP;
case "NORTH" -> Direction.NORTH;
case "SOUTH" -> Direction.SOUTH;
case "WEST" -> Direction.WEST;
case "EAST" -> Direction.EAST;
default -> null;
};
if (dir == null) {
throw new IllegalArgumentException("Invalid direction on init mapping: " + lodDir);
}
directions[lodDir.ordinal()] = dir;
lodDirections = new LodDirection[lodDirs.length];
for (LodDirection lodDir : lodDirs) {
Direction dir = Direction.byName(lodDir.name());
directions[lodDir.ordinal()] = dir;
lodDirections[dir.ordinal()] = lodDir;
}
}
public static BlockPos Convert(DhBlockPos wrappedPos) {
return new BlockPos(wrappedPos.x, wrappedPos.y, wrappedPos.z);
public static BlockPos Convert(AbstractBlockPosWrapper wrappedPos) {
return new BlockPos(wrappedPos.getX(),wrappedPos.getY(), wrappedPos.getZ());
}
public static ChunkPos Convert(DhChunkPos wrappedPos) {
return new ChunkPos(wrappedPos.x, wrappedPos.z);
}
public static Direction Convert(ELodDirection lodDirection)
public static Direction Convert(LodDirection lodDirection)
{
return directions[lodDirection.ordinal()];
}
public static ELodDirection Convert(Direction direction)
public static LodDirection Convert(Direction direction)
{
return lodDirections[direction.ordinal()];
}
public static void DebugCheckAllPackers() {
BiConsumer<Integer, Integer> func = (x, z) -> DhChunkPos._DebugCheckPacker(x,z,ChunkPos.asLong(x,z));
func.accept(0,0);
func.accept(12345,134);
func.accept(-12345,-134);
func.accept(-30000000/16,30000000/16);
func.accept(30000000/16,-30000000/16);
func.accept(30000000/16,30000000/16);
func.accept(-30000000/16,-30000000/16);
Consumer<BlockPos> func2 = (p) -> DhBlockPos._DebugCheckPacker(p.getX(),p.getY(),p.getZ(),p.asLong());
func2.accept(new BlockPos(0,0,0));
func2.accept(new BlockPos(12345,134,123));
func2.accept(new BlockPos(-12345,-134,-80));
func2.accept(new BlockPos(-30000000, 2047, 30000000));
func2.accept(new BlockPos(30000000, -2048, -30000000));
func2.accept(new BlockPos(30000000, 2047, 30000000));
func2.accept(new BlockPos(-30000000, -2048, -30000000));
}
}
@@ -1,26 +1,8 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
import net.minecraft.client.Minecraft;
/**
* @author James Seibel
@@ -54,9 +36,4 @@ public class VersionConstants implements IVersionConstants
{
return false;
}
@Override
public String getMinecraftVersion() {
return Minecraft.getInstance().getGame().getVersion().getId();
}
}
@@ -1,146 +1,94 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
* 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
* it under the terms of the GNU 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.
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.common.wrappers;
import com.seibel.lod.api.interfaces.override.worldGenerator.IDhApiWorldGenerator;
import com.seibel.lod.common.wrappers.block.BlockStateWrapper;
import com.seibel.lod.common.wrappers.block.BiomeWrapper;
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
import com.seibel.lod.core.level.IDhLevel;
import com.seibel.lod.core.level.IDhServerLevel;
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper;
import com.seibel.lod.common.wrappers.block.BlockPosWrapper;
import com.seibel.lod.common.wrappers.chunk.ChunkPosWrapper;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.chunk.ChunkAccess;
import java.io.IOException;
/**
* This handles creating abstract wrapper objects.
*
* @author James Seibel
* @version 2022-12-5
* @version 11-20-2021
*/
public class WrapperFactory implements IWrapperFactory
{
public static final WrapperFactory INSTANCE = new WrapperFactory();
@Override
public AbstractBatchGenerationEnvionmentWrapper createBatchGenerator(IDhLevel targetLevel)
public AbstractBlockPosWrapper createBlockPos()
{
if (targetLevel instanceof IDhServerLevel)
{
return new BatchGenerationEnvironment((IDhServerLevel) targetLevel);
}
else
{
throw new IllegalArgumentException("The target level must be a server-side level.");
}
return new BlockPosWrapper();
}
@Override
public IBiomeWrapper deserializeBiomeWrapper(String str) throws IOException { return BiomeWrapper.deserialize(str); }
@Override
public IBlockStateWrapper deserializeBlockStateWrapper(String str) throws IOException { return BlockStateWrapper.deserialize(str); }
@Override
public IBlockStateWrapper getAirBlockStateWrapper() { return BlockStateWrapper.AIR; }
/**
* Note: when this is updated for different MC versions, make sure you also update the documentation in
* {@link IDhApiWorldGenerator#generateChunks} and the type list in {@link WrapperFactory#createChunkWrapperErrorMessage}. <br><br>
*
* For full method documentation please see: {@link IWrapperFactory#createChunkWrapper}
* @see IWrapperFactory#createChunkWrapper
*/
public IChunkWrapper createChunkWrapper(Object[] objectArray) throws ClassCastException
public AbstractBlockPosWrapper createBlockPos(int x, int y, int z)
{
if (objectArray.length == 1 && objectArray[0] instanceof IChunkWrapper) // alternate option if "instanceof" can't be compiled down to older JRE versions "IChunkWrapper.class.isInstance(objectArray[0])" Feel free to delete this comment if we've compiled the mod for 1.16 or earlier - James
{
try
{
// this path should only happen when called by Distant Horizons code
// API implementors should never hit this path
return (IChunkWrapper) objectArray[0];
}
catch (Exception e)
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
}
// correct number of parameters from the API
else if (objectArray.length == 2)
{
// chunk
if (!(objectArray[0] instanceof ChunkAccess chunk))
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
// light source
if (!(objectArray[1] instanceof LevelReader lightSource))
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
return new ChunkWrapper(chunk, lightSource, /*A DH wrapped level isn't necessary*/null);
}
// incorrect number of parameters from the API
else
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
}
/** Note: when this is updated for different MC versions, make sure you also update the documentation in {@link IDhApiWorldGenerator#generateChunks}. */
private static String createChunkWrapperErrorMessage(Object[] objectArray)
{
StringBuilder message = new StringBuilder(
"Chunk wrapper creation failed. \n" +
"Expected parameters: " +
"[" + ChunkAccess.class.getName() + "], " +
"[" + LevelReader.class.getName() + "]. \n");
if (objectArray.length != 0)
{
message.append("Given parameters: ");
for (Object obj : objectArray)
{
message.append("[").append(obj.getClass().getName()).append("], ");
}
}
else
{
message.append(" No parameters given.");
}
return message.toString();
return new BlockPosWrapper(x, y, z);
}
@Override
public AbstractChunkPosWrapper createChunkPos()
{
return new ChunkPosWrapper();
}
@Override
public AbstractChunkPosWrapper createChunkPos(long xAndZPositionCombined)
{
return new ChunkPosWrapper(xAndZPositionCombined);
}
@Override
public AbstractChunkPosWrapper createChunkPos(int x, int z)
{
return new ChunkPosWrapper(x, z);
}
@Override
public AbstractChunkPosWrapper createChunkPos(AbstractChunkPosWrapper newChunkPos)
{
return new ChunkPosWrapper(newChunkPos);
}
@Override
public AbstractChunkPosWrapper createChunkPos(AbstractBlockPosWrapper blockPos)
{
return new ChunkPosWrapper(blockPos);
}
public AbstractBatchGenerationEnvionmentWrapper createBatchGenerator(LodBuilder newLodBuilder,
LodDimension newLodDimension, IWorldWrapper worldWrapper)
{
return new BatchGenerationEnvironment(worldWrapper, newLodBuilder, newLodDimension);
}
}
@@ -1,19 +1,19 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
* 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
* it under the terms of the GNU 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.
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@@ -1,114 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.block;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import com.google.common.collect.ImmutableBiMap;
import com.google.gson.JsonParser;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.Lifecycle;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.core.Holder;
#if POST_MC_1_19
import net.minecraft.data.worldgen.biome.EndBiomes;
import net.minecraft.data.worldgen.biome.NetherBiomes;
#endif
import net.minecraft.resources.RegistryFixedCodec;
import net.minecraft.resources.RegistryOps;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
/** This class wraps the minecraft BlockPos.Mutable (and BlockPos) class */
public class BiomeWrapper implements IBiomeWrapper
{
#if PRE_MC_1_18_2
public static final ConcurrentMap<Biome, BiomeWrapper> biomeWrapperMap = new ConcurrentHashMap<>();
public final Biome biome;
#else
public static final ConcurrentMap<Holder<Biome>, BiomeWrapper> biomeWrapperMap = new ConcurrentHashMap<>();
public final Holder<Biome> biome;
#endif
static public IBiomeWrapper getBiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder<Biome> #endif biome)
{
return biomeWrapperMap.computeIfAbsent(biome, BiomeWrapper::new);
}
private BiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder<Biome> #endif biome)
{
this.biome = biome;
}
@Override
public String getName()
{
#if PRE_MC_1_18_2
return biome.toString();
#else
return biome.unwrapKey().orElse(Biomes.THE_VOID).registry().toString();
#endif
}
@Override
public String serialize() {
//FIXME: Pass in a level obj
String data = Biome.CODEC.encodeStart(RegistryOps.create(JsonOps.INSTANCE, Minecraft.getInstance().level.registryAccess()),
biome).get().orThrow().toString();
return data;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BiomeWrapper that = (BiomeWrapper) o;
return Objects.equals(biome, that.biome);
}
@Override
public int hashCode() {
return Objects.hash(biome);
}
public static IBiomeWrapper deserialize(String str) throws IOException {
try {
#if PRE_MC_1_18_2 Biome #else
Holder<Biome> #endif
biome = Biome.CODEC.decode(RegistryOps.create(JsonOps.INSTANCE, Minecraft.getInstance().level.registryAccess()),
JsonParser.parseString(str)).get().orThrow().getFirst();
return getBiomeWrapper(biome);
} catch (Exception e) {
throw new IOException("Failed to deserialize biome wrapper", e);
}
}
@Override
public Object getWrappedMcObject_UNSAFE() { return this.biome; }
}
@@ -0,0 +1,27 @@
package com.seibel.lod.common.wrappers.block;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.state.BlockState;
public class BlockDetailMap
{
private static ConcurrentHashMap<BlockState, BlockDetailWrapper> map = new ConcurrentHashMap<BlockState, BlockDetailWrapper>();
private BlockDetailMap() {}
public static BlockDetailWrapper getOrMakeBlockDetailCache(BlockState bs, BlockPos pos, LevelReader getter) {
BlockDetailWrapper cache = map.get(bs);
if (cache != null) return cache;
if (bs.getFluidState().isEmpty()) {
cache = BlockDetailWrapper.make(bs, pos, getter);
} else {
cache = BlockDetailWrapper.make(bs.getFluidState().createLegacyBlock(), pos, getter);
}
BlockDetailWrapper cacheCAS = map.putIfAbsent(bs, cache);
return cacheCAS==null ? cache : cacheCAS;
}
}
@@ -0,0 +1,326 @@
package com.seibel.lod.common.wrappers.block;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
import com.seibel.lod.common.Config;
import com.seibel.lod.common.wrappers.McObjectConverter;
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.client.color.block.BlockTintCache;
import net.minecraft.client.renderer.BiomeColors;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Cursor3D;
import net.minecraft.core.Direction;
import net.minecraft.world.level.*;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.FlowerBlock;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.RotatedPillarBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;
public class BlockDetailWrapper extends IBlockDetailWrapper
{
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
public static final int FLOWER_COLOR_SCALE = 5;
public static final Random random = new Random(0);
enum ColorMode {
Default,
Flower,
Leaves;
static ColorMode getColorMode(Block b) {
if (b instanceof LeavesBlock) return Leaves;
if (b instanceof FlowerBlock) return Flower;
return Default;
}
}
//TODO: Perhaps make this not just use the first frame?
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode) {
int count = 0;
double alpha = 0;
double red = 0;
double green = 0;
double blue = 0;
int tempColor;
{
// textures normally use u and v instead of x and y
for (int u = 0; u < texture.getWidth(); u++)
{
for (int v = 0; v < texture.getHeight(); v++)
{
//note: Minecraft color format is: 0xAA BB GG RR
//________ DH mod color format is: 0xAA RR GG BB
//OpenGL RGBA format native order: 0xRR GG BB AA
//_ OpenGL RGBA format Java Order: 0xAA BB GG RR
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
double r = ((tempColor & 0x000000FF) )/255.;
double g = ((tempColor & 0x0000FF00) >>> 8)/255.;
double b = ((tempColor & 0x00FF0000) >>> 16)/255.;
double a = ((tempColor & 0xFF000000) >>> 24)/255.;
int scale = 1;
if (colorMode == ColorMode.Leaves) {
r *= a;
g *= a;
b *= a;
a = 1.;
} else if (a==0.) {
continue;
} else if (colorMode == ColorMode.Flower && (g+0.1<b || g+0.1<r)) {
scale = FLOWER_COLOR_SCALE;
}
count += scale;
alpha += a*a*scale;
red += r*r*scale;
green += g*g*scale;
blue += b*b*scale;
}
}
}
if (count == 0)
// this block is entirely transparent
tempColor = ColorUtil.rgbToInt(255,255,0,255);
else
{
// determine the average color
tempColor = ColorUtil.rgbToInt(
(int) (Math.sqrt(alpha/count)*255.),
(int) (Math.sqrt(red / count)*255.),
(int) (Math.sqrt(green / count)*255.),
(int) (Math.sqrt(blue / count)*255.));
}
// TODO: Remove this when transparency is added!
double colorAlpha = ColorUtil.getAlpha(tempColor)/255.;
tempColor = ColorUtil.rgbToInt(
ColorUtil.getAlpha(tempColor),
(int)(ColorUtil.getRed(tempColor) * colorAlpha),
(int)(ColorUtil.getGreen(tempColor) * colorAlpha),
(int)(ColorUtil.getBlue(tempColor) * colorAlpha)
);
return tempColor;
}
private static final Block[] BLOCK_TO_AVOID = {Blocks.AIR, Blocks.CAVE_AIR, Blocks.BARRIER};
private static final Direction[] DIRECTION_ORDER = {Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN};
private static boolean isBlockToBeAvoid(Block b) {
for (Block bta : BLOCK_TO_AVOID)
if (bta==b) return true;
return false;
}
final BlockState state;
final BlockPos samplePos;
final LevelReader sampleGetter;
boolean isShapeResolved = false;
boolean[] dontOccludeFaces = null;
boolean noCollision = false;
boolean noFullFace = false;
boolean isColorResolved = false;
int baseColor = 0; //TODO: Impl per-face color
boolean needShade = true;
boolean needPostTinting = false;
int tintIndex = 0;
public static BlockDetailWrapper NULL_BLOCK_DETAIL = new BlockDetailWrapper();
public BlockDetailWrapper(BlockState state, BlockPos pos, LevelReader getter) {
this.state = state;
this.samplePos = pos;
this.sampleGetter = getter;
}
private BlockDetailWrapper() {
this.state = null;
this.samplePos = null;
this.sampleGetter = null;
}
static BlockDetailWrapper make(BlockState bs, BlockPos pos, LevelReader getter) {
if(!bs.getFluidState().isEmpty()) { // Is a fluidBlock
if (isBlockToBeAvoid(bs.getBlock())) return NULL_BLOCK_DETAIL;
if (bs.isAir()) return NULL_BLOCK_DETAIL;
return new BlockDetailWrapper(bs, pos, getter);
} else {
if (bs.getRenderShape() != RenderShape.MODEL) return NULL_BLOCK_DETAIL;
if (isBlockToBeAvoid(bs.getBlock())) return NULL_BLOCK_DETAIL;
return new BlockDetailWrapper(bs, pos, getter);
}
}
private void resolveShapes() {
if (isShapeResolved) return;
if (state.getFluidState().isEmpty()) {
noCollision = state.getCollisionShape(sampleGetter, samplePos).isEmpty();
dontOccludeFaces = new boolean[6];
if (state.canOcclude()) {
/* FIXME: Figure out how or if needed to impl per-face culling?
for (Direction dir : Direction.values()) {
dontOccludeFaces[McObjectConverter.Convert(dir).ordinal()]
= state.getFaceOcclusionShape(sampleGetter, samplePos, dir).isEmpty();
}*/
} else {
Arrays.fill(dontOccludeFaces, true);
}
VoxelShape voxelShape = state.getShape(sampleGetter, samplePos);
if (voxelShape.isEmpty()) {
noFullFace = true;
} else {
AABB bbox = voxelShape.bounds();
double xWidth = (bbox.maxX - bbox.minX);
double yWidth = (bbox.maxY - bbox.minY);
double zWidth = (bbox.maxZ - bbox.minZ);
noFullFace = xWidth < 1 && zWidth < 1 && yWidth < 1;
}
} else { // Liquid Block
dontOccludeFaces = new boolean[6];
}
isShapeResolved = true;
}
private void resolveColors() {
if (isColorResolved) return;
if (state.getFluidState().isEmpty()) {
List<BakedQuad> quads = null;
for (Direction direction : DIRECTION_ORDER)
{
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
getBlockModel(state).getQuads(state, direction, random);
if (!quads.isEmpty() &&
!(state.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP))
break;
};
if (quads == null || quads.isEmpty()) {
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
getBlockModel(state).getQuads(state, null, random);
}
if (quads != null && !quads.isEmpty()) {
needPostTinting = quads.get(0).isTinted();
needShade = quads.get(0).isShade();
tintIndex = quads.get(0).getTintIndex();
baseColor = calculateColorFromTexture(quads.get(0).getSprite(),
ColorMode.getColorMode(state.getBlock()));
} else { // Backup method.
needPostTinting = false;
needShade = false;
tintIndex = 0;
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(state),
ColorMode.getColorMode(state.getBlock()));
}
} else { // Liquid Block
needPostTinting = true;
needShade = false;
tintIndex = 0;
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(state),
ColorMode.getColorMode(state.getBlock()));
}
isColorResolved = true;
}
private BlockAndTintGetter wrapColorResolver(LevelReader level) {
int blendDistance = CONFIG.client().graphics().quality().getLodBiomeBlending();
if (blendDistance == 0) {
return new TintGetterOverrideFast(level);
} else {
return new TintGetterOverrideSmooth(level, blendDistance);
}
}
@Override
public int getAndResolveFaceColor(LodDirection dir, IChunkWrapper chunk, AbstractBlockPosWrapper blockPos)
{
// FIXME: impl per-face colors
resolveColors();
if (!needPostTinting) return baseColor;
int tintColor = Minecraft.getInstance().getBlockColors()
.getColor(state, wrapColorResolver(((ChunkWrapper)chunk).getColorResolver()),
McObjectConverter.Convert(blockPos), tintIndex);
if (tintColor == -1) return baseColor;
return ColorUtil.multiplyARGBwithRGB(baseColor, tintColor);
}
@Override
public boolean hasFaceCullingFor(LodDirection dir)
{
resolveShapes();
return !dontOccludeFaces[dir.ordinal()];
}
@Override
public boolean hasNoCollision()
{
resolveShapes();
return noCollision;
}
@Override
public boolean noFaceIsFullFace()
{
resolveShapes();
return noFullFace;
}
@Override
public String serialize()
{
// FIXME: Impl this for the blockState Storage stuff
return null;
}
@Override
protected boolean isSame(IBlockDetailWrapper iBlockDetail)
{
return ((BlockDetailWrapper)iBlockDetail).state.getBlock().equals(state.getBlock());
}
}
@@ -0,0 +1,84 @@
package com.seibel.lod.common.wrappers.block;
import java.util.Objects;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
import net.minecraft.core.BlockPos;
/**
* @author James Seibel
* @version 11-21-2021
*/
public class BlockPosWrapper extends AbstractBlockPosWrapper
{
private final BlockPos.MutableBlockPos blockPos;
public BlockPosWrapper()
{
this.blockPos = new BlockPos.MutableBlockPos(0,0,0);
}
public BlockPosWrapper(int x, int y, int z)
{
this.blockPos = new BlockPos.MutableBlockPos(x, y, z);
}
@Override
public void set(int x, int y, int z)
{
blockPos.set(x, y, z);
}
@Override
public int getX()
{
return blockPos.getX();
}
@Override
public int getY()
{
return blockPos.getY();
}
@Override
public int getZ()
{
return blockPos.getZ();
}
@Override
public int get(LodDirection.Axis axis)
{
return axis.choose(getX(), getY(), getZ());
}
public BlockPos.MutableBlockPos getBlockPos()
{
return blockPos;
}
@Override public boolean equals(Object o)
{
return blockPos.equals(o);
}
@Override public int hashCode()
{
return Objects.hash(blockPos);
}
@Override
public BlockPosWrapper offset(int x, int y, int z)
{
blockPos.set(blockPos.getX() + x, blockPos.getY() + y, blockPos.getZ() + z);
return this;
}
}
@@ -1,87 +0,0 @@
package com.seibel.lod.common.wrappers.block;
import com.google.gson.JsonParser;
import com.mojang.serialization.JsonOps;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
import net.minecraft.world.level.block.state.BlockState;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
public class BlockStateWrapper implements IBlockStateWrapper
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public static final BlockStateWrapper AIR = new BlockStateWrapper(null);
public static ConcurrentHashMap<BlockState, BlockStateWrapper> cache = new ConcurrentHashMap<>();
public static BlockStateWrapper fromBlockState(BlockState blockState)
{
if (blockState == null || blockState.isAir())
return AIR;
if (blockState.getFluidState().isEmpty())
return cache.computeIfAbsent(blockState, BlockStateWrapper::new);
else
return cache.computeIfAbsent(blockState.getFluidState().createLegacyBlock(), BlockStateWrapper::new);
}
public final BlockState blockState;
BlockStateWrapper(BlockState blockState) {
this.blockState = blockState;
//LOGGER.info("Created BlockStateWrapper for {}", blockState);
}
@Override
public String serialize() {
if (blockState == null) {
return "AIR";
}
return BlockState.CODEC.encodeStart(JsonOps.COMPRESSED, blockState).get().orThrow().toString();
}
public static BlockStateWrapper deserialize(String str) throws IOException {
if (str.equals("AIR")) {
return AIR;
}
try {
return new BlockStateWrapper(
BlockState.CODEC.decode(JsonOps.COMPRESSED, JsonParser.parseString(str)).get().orThrow().getFirst()
);
} catch (Exception e) {
throw new IOException("Failed to deserialize BlockStateWrapper", e);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BlockStateWrapper that = (BlockStateWrapper) o;
return Objects.equals(blockState, that.blockState);
}
@Override
public int hashCode() {
return Objects.hash(blockState);
}
@Override
public Object getWrappedMcObject_UNSAFE() { return this.blockState; }
@Override
public boolean isAir() { return this.isAir(this.blockState); }
public boolean isAir(BlockState blockState) { return blockState == null || blockState.isAir(); }
}
@@ -1,22 +1,3 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.block;
@@ -37,16 +18,11 @@ public class TextureAtlasSpriteWrapper {
* The code has been modified to use TextureAtlasSprite
*/
public static int getPixelRGBA(TextureAtlasSprite sprite, int frameIndex, int x, int y) {
#if PRE_MC_1_17_1
return sprite.mainImage[0].getPixelRGBA(
x + sprite.framesX[frameIndex] * sprite.getWidth(),
y + sprite.framesY[frameIndex] * sprite.getHeight());
#else
if (sprite.animatedTexture != null) {
x += sprite.animatedTexture.getFrameX(frameIndex) * sprite.width;
y += sprite.animatedTexture.getFrameY(frameIndex) * sprite.height;
}
return sprite.mainImage[0].getPixelRGBA(x, y);
#endif
}
}
@@ -1,25 +1,5 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.block;
import com.seibel.lod.common.LodCommonMain;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.Util;
import net.minecraft.client.color.block.BlockTintCache;
@@ -53,21 +33,17 @@ public class TintGetterOverrideFast implements BlockAndTintGetter {
}
private Biome _getBiome(BlockPos pos) {
#if POST_MC_1_18_2
#if MC_VERSION_1_18_2
return parent.getBiome(pos).value();
#else
#elif MC_VERSION_1_18_1
return parent.getBiome(pos);
#endif
}
@Override
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) {
if (LodCommonMain.forgeMethodCaller != null) {
return LodCommonMain.forgeMethodCaller.colorResolverGetColor(colorResolver, _getBiome(blockPos),
blockPos.getX(), blockPos.getZ());
} else {
return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ());
}
Biome b = _getBiome(blockPos);
return colorResolver.getColor(b, blockPos.getX(), blockPos.getZ());
}
@Override
@@ -101,6 +77,10 @@ public class TintGetterOverrideFast implements BlockAndTintGetter {
return parent.getBlockEntity(blockPos);
}
@Override
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) {
return parent.getBlockEntity(blockPos, blockEntityType);
}
@Override
public BlockState getBlockState(BlockPos blockPos) {
@@ -127,6 +107,11 @@ public class TintGetterOverrideFast implements BlockAndTintGetter {
return parent.getBlockStates(aABB);
}
@Override
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) {
return parent.isBlockInLine(clipBlockStateContext);
}
@Override
public BlockHitResult clip(ClipContext clipContext) {
return parent.clip(clipContext);
@@ -148,22 +133,6 @@ public class TintGetterOverrideFast implements BlockAndTintGetter {
return parent.getBlockFloorHeight(blockPos);
}
@Override
public int getMaxBuildHeight() {
return parent.getMaxBuildHeight();
}
#if POST_MC_1_17_1
@Override
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) {
return parent.getBlockEntity(blockPos, blockEntityType);
}
@Override
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) {
return parent.isBlockInLine(clipBlockStateContext);
}
@Override
public int getHeight() {
return parent.getHeight();
@@ -174,6 +143,11 @@ public class TintGetterOverrideFast implements BlockAndTintGetter {
return parent.getMinBuildHeight();
}
@Override
public int getMaxBuildHeight() {
return parent.getMaxBuildHeight();
}
@Override
public int getSectionsCount() {
return parent.getSectionsCount();
@@ -213,5 +187,4 @@ public class TintGetterOverrideFast implements BlockAndTintGetter {
public int getSectionYFromSectionIndex(int i) {
return parent.getSectionYFromSectionIndex(i);
}
#endif
}
@@ -1,25 +1,5 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.block;
import com.seibel.lod.common.LodCommonMain;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.Util;
import net.minecraft.client.color.block.BlockTintCache;
@@ -54,10 +34,10 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter {
}
private Biome _getBiome(BlockPos pos) {
#if POST_MC_1_18_2
#if MC_VERSION_1_18_2
return parent.getBiome(pos).value();
#else
return parent.getBiome(pos);
#elif MC_VERSION_1_18_1
return parent.getBiome(pos);
#endif
}
@@ -75,14 +55,7 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter {
while (cursor3D.advance())
{
mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
int n;
if (LodCommonMain.forgeMethodCaller != null) {
n = LodCommonMain.forgeMethodCaller.colorResolverGetColor(colorResolver, _getBiome(mutableBlockPos),
mutableBlockPos.getX(), mutableBlockPos.getZ());
} else {
n = colorResolver.getColor(_getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
}
int n = colorResolver.getColor(_getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
k += (n & 0xFF0000) >> 16;
l += (n & 0xFF00) >> 8;
m += n & 0xFF;
@@ -126,6 +99,11 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter {
return parent.getBlockEntity(blockPos);
}
@Override
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) {
return parent.getBlockEntity(blockPos, blockEntityType);
}
@Override
public BlockState getBlockState(BlockPos blockPos) {
return parent.getBlockState(blockPos);
@@ -151,6 +129,11 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter {
return parent.getBlockStates(aABB);
}
@Override
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) {
return parent.isBlockInLine(clipBlockStateContext);
}
@Override
public BlockHitResult clip(ClipContext clipContext) {
return parent.clip(clipContext);
@@ -172,22 +155,6 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter {
return parent.getBlockFloorHeight(blockPos);
}
@Override
public int getMaxBuildHeight() {
return parent.getMaxBuildHeight();
}
#if POST_MC_1_17_1
@Override
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) {
return parent.getBlockEntity(blockPos, blockEntityType);
}
@Override
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) {
return parent.isBlockInLine(clipBlockStateContext);
}
@Override
public int getHeight() {
return parent.getHeight();
@@ -198,6 +165,11 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter {
return parent.getMinBuildHeight();
}
@Override
public int getMaxBuildHeight() {
return parent.getMaxBuildHeight();
}
@Override
public int getSectionsCount() {
return parent.getSectionsCount();
@@ -237,5 +209,4 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter {
public int getSectionYFromSectionIndex(int i) {
return parent.getSectionYFromSectionIndex(i);
}
#endif
}
@@ -1,91 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.block;
import com.seibel.lod.common.LodCommonMain;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.world.level.*;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class TintWithoutLevelOverrider implements BlockAndTintGetter {
final BiomeWrapper biome;
public TintWithoutLevelOverrider(BiomeWrapper biome) {
this.biome = biome;
}
@Override
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) {
return colorResolver.getColor(_unwrap(biome.biome), blockPos.getX(), blockPos.getZ());
}
private Biome _unwrap(#if POST_MC_1_18_2 Holder<Biome> #else Biome #endif biome) {
#if POST_MC_1_18_2
return biome.value();
#else
return biome;
#endif
}
@Override
public float getShade(Direction direction, boolean shade) {
throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
public LevelLightEngine getLightEngine() {
throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Nullable
@Override
public BlockEntity getBlockEntity(BlockPos pos) {
throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
public BlockState getBlockState(BlockPos pos) {
throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
public FluidState getFluidState(BlockPos pos) {
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
public int getHeight() {
throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
public int getMinBuildHeight() {
throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
}
@@ -1,115 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.block;
import com.seibel.lod.common.LodCommonMain;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Cursor3D;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import org.jetbrains.annotations.Nullable;
public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter {
final BiomeWrapper biome;
public int smoothingRange;
public TintWithoutLevelSmoothOverrider(BiomeWrapper biome, int smoothingRange) {
this.biome = biome;
this.smoothingRange = smoothingRange;
}
@Override
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) {
return colorResolver.getColor(_unwrap(biome.biome), blockPos.getX(), blockPos.getZ());
}
private Biome _unwrap(#if POST_MC_1_18_2 Holder<Biome> #else Biome #endif biome) {
#if POST_MC_1_18_2
return biome.value();
#else
return biome;
#endif
}
//
// public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
// {
// int i = smoothingRange;
// if (i == 0)
// return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ());
// int j = (i * 2 + 1) * (i * 2 + 1);
// int k = 0;
// int l = 0;
// int m = 0;
// Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i);
// BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
// while (cursor3D.advance())
// {
// mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
// int n;
// if (LodCommonMain.forgeMethodCaller != null) {
// n = LodCommonMain.forgeMethodCaller.colorResolverGetColor(colorResolver, _getBiome(mutableBlockPos),
// mutableBlockPos.getX(), mutableBlockPos.getZ());
// } else {
// n = colorResolver.getColor(_getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
// }
//
// k += (n & 0xFF0000) >> 16;
// l += (n & 0xFF00) >> 8;
// m += n & 0xFF;
// }
// return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
// }
@Override
public float getShade(Direction direction, boolean shade) {
throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
public LevelLightEngine getLightEngine() {
throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Nullable
@Override
public BlockEntity getBlockEntity(BlockPos pos) {
throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
public BlockState getBlockState(BlockPos pos) {
throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
public FluidState getFluidState(BlockPos pos) {
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
public int getHeight() {
throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
public int getMinBuildHeight() {
throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
}
@@ -1,25 +0,0 @@
package com.seibel.lod.common.wrappers.block.cache;
import com.seibel.lod.common.wrappers.block.BiomeWrapper;
import com.seibel.lod.common.wrappers.world.ClientLevelWrapper;
import com.seibel.lod.core.pos.DhBlockPos;
import net.minecraft.world.level.block.state.BlockState;
import java.util.concurrent.ConcurrentHashMap;
public class ClientBlockDetailMap {
private final ConcurrentHashMap<BlockState, ClientBlockStateCache> blockCache = new ConcurrentHashMap<>();
//private final ConcurrentHashMap<#if PRE_MC_1_18_2 Biome #else Holder<Biome> #endif, Biome> biomeMap = new ConcurrentHashMap<>();
private final ClientLevelWrapper level;
public ClientBlockDetailMap(ClientLevelWrapper level) { this.level = level; }
public ClientBlockStateCache getBlockStateData(BlockState state, DhBlockPos pos) { //TODO: Allow a per pos unique setting
return blockCache.computeIfAbsent(state, (s) -> new ClientBlockStateCache(s, level, new DhBlockPos(0,0,0)));
}
public void clear() { blockCache.clear(); }
public int getColor(BlockState state, BiomeWrapper biome, DhBlockPos pos) {
return getBlockStateData(state, pos).getAndResolveFaceColor(biome);
}
}
@@ -1,186 +0,0 @@
package com.seibel.lod.common.wrappers.block.cache;
import com.seibel.lod.common.wrappers.McObjectConverter;
import com.seibel.lod.common.wrappers.block.*;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.pos.DhBlockPos;
import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.FlowerBlock;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.RotatedPillarBlock;
#if POST_MC_1_19
import net.minecraft.util.RandomSource;
#endif
import net.minecraft.world.level.block.state.BlockState;
import org.apache.logging.log4j.Logger;
import java.util.List;
import java.util.Random;
/**
*
* @version 2022-9-16
*/
public class ClientBlockStateCache
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
#if PRE_MC_1_19
public static final Random random = new Random(0);
#else
public static final RandomSource random = RandomSource.create();
#endif
public final BlockState state;
public final LevelReader level;
public final BlockPos pos;
public ClientBlockStateCache(BlockState blockState, IClientLevelWrapper samplingLevel, DhBlockPos samplingPos) {
state = blockState;
level = (LevelReader) samplingLevel.getWrappedMcObject_UNSAFE();
pos = McObjectConverter.Convert(samplingPos);
resolveColors();
//LOGGER.info("ClientBlocKCache created for {}", blockState);
}
boolean isColorResolved = false;
int baseColor = 0; //TODO: Impl per-face color
boolean needShade = true;
boolean needPostTinting = false;
int tintIndex = 0;
public static final int FLOWER_COLOR_SCALE = 5;
enum ColorMode {
Default,
Flower,
Leaves;
static ColorMode getColorMode(Block b) {
if (b instanceof LeavesBlock) return Leaves;
if (b instanceof FlowerBlock) return Flower;
return Default;
}
}
//TODO: Perhaps make this not just use the first frame?
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode) {
int count = 0;
double alpha = 0;
double red = 0;
double green = 0;
double blue = 0;
int tempColor;
{
// textures normally use u and v instead of x and y
for (int u = 0; u < texture.getWidth(); u++)
{
for (int v = 0; v < texture.getHeight(); v++)
{
//note: Minecraft color format is: 0xAA BB GG RR
//________ DH mod color format is: 0xAA RR GG BB
//OpenGL RGBA format native order: 0xRR GG BB AA
//_ OpenGL RGBA format Java Order: 0xAA BB GG RR
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
double r = ((tempColor & 0x000000FF) )/255.;
double g = ((tempColor & 0x0000FF00) >>> 8)/255.;
double b = ((tempColor & 0x00FF0000) >>> 16)/255.;
double a = ((tempColor & 0xFF000000) >>> 24)/255.;
int scale = 1;
if (colorMode == ColorMode.Leaves) {
r *= a;
g *= a;
b *= a;
a = 1.;
} else if (a==0.) {
continue;
} else if (colorMode == ColorMode.Flower && (g+0.1<b || g+0.1<r)) {
scale = FLOWER_COLOR_SCALE;
}
count += scale;
alpha += a*a*scale;
red += r*r*scale;
green += g*g*scale;
blue += b*b*scale;
}
}
}
if (count == 0)
// this block is entirely transparent
tempColor = ColorUtil.rgbToInt(0,255,255,255);
else
{
// determine the average color
tempColor = ColorUtil.rgbToInt(
(int) (Math.sqrt(alpha/count)*255.),
(int) (Math.sqrt(red / count)*255.),
(int) (Math.sqrt(green / count)*255.),
(int) (Math.sqrt(blue / count)*255.));
}
return tempColor;
}
private static final Direction[] DIRECTION_ORDER = {Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN};
private void resolveColors() {
if (isColorResolved) return;
if (state.getFluidState().isEmpty()) {
List<BakedQuad> quads = null;
for (Direction direction : DIRECTION_ORDER)
{
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
getBlockModel(state).getQuads(state, direction, random);
if (quads != null && !quads.isEmpty() &&
!(state.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP))
break;
};
if (quads == null || quads.isEmpty()) {
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
getBlockModel(state).getQuads(state, null, random);
}
if (quads != null && !quads.isEmpty()) {
needPostTinting = quads.get(0).isTinted();
needShade = quads.get(0).isShade();
tintIndex = quads.get(0).getTintIndex();
baseColor = calculateColorFromTexture(
#if PRE_MC_1_17_1 quads.get(0).sprite,
#else quads.get(0).getSprite(), #endif
ColorMode.getColorMode(state.getBlock()));
} else { // Backup method.
needPostTinting = false;
needShade = false;
tintIndex = 0;
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(state),
ColorMode.getColorMode(state.getBlock()));
}
} else { // Liquid Block
needPostTinting = true;
needShade = false;
tintIndex = 0;
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(state),
ColorMode.getColorMode(state.getBlock()));
}
isColorResolved = true;
}
public int getAndResolveFaceColor(BiomeWrapper biome)
{
// FIXME: impl per-face colors
if (!needPostTinting) return baseColor;
int tintColor = Minecraft.getInstance().getBlockColors()
.getColor(state, new TintWithoutLevelOverrider(biome), pos, tintIndex);
if (tintColor == -1) return baseColor;
return ColorUtil.multiplyARGBwithRGB(baseColor, tintColor);
}
}
@@ -1,41 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.block.cache;
import java.util.concurrent.ConcurrentHashMap;
import com.seibel.lod.common.wrappers.world.ServerLevelWrapper;
import com.seibel.lod.core.pos.DhBlockPos;
import net.minecraft.world.level.block.state.BlockState;
public class ServerBlockDetailMap
{
private final ConcurrentHashMap<BlockState, ServerBlockStateCache> blockCache = new ConcurrentHashMap<>();
//private final ConcurrentHashMap<#if PRE_MC_1_18_2 Biome #else Holder<Biome> #endif, Biome> biomeMap = new ConcurrentHashMap<>();
private final ServerLevelWrapper level;
public ServerBlockDetailMap(ServerLevelWrapper level) { this.level = level; }
public ServerBlockStateCache getBlockStateData(BlockState state, DhBlockPos pos) { //TODO: Allow a per pos unique setting
return blockCache.computeIfAbsent(state, (s) -> new ServerBlockStateCache(s, level, new DhBlockPos(0,0,0)));
}
public void clear() { blockCache.clear(); }
}
@@ -1,77 +0,0 @@
package com.seibel.lod.common.wrappers.block.cache;
import com.seibel.lod.common.wrappers.McObjectConverter;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.pos.DhBlockPos;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.apache.logging.log4j.Logger;
import java.util.Arrays;
/**
*
* @version 2022-9-16
*/
public class ServerBlockStateCache
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public final BlockState state;
public final LevelReader level;
public final BlockPos pos;
public ServerBlockStateCache(BlockState blockState, ILevelWrapper samplingLevel, DhBlockPos samplingPos) {
state = blockState;
level = (LevelReader) samplingLevel.getWrappedMcObject_UNSAFE();
pos = McObjectConverter.Convert(samplingPos);
resolveShapes();
//LOGGER.info("ServerBlockState created for {}", blockState);
}
boolean noCollision = false;
boolean[] occludeFaces = null;
boolean[] fullFaces = null;
boolean isShapeResolved = false;
public void resolveShapes() {
if (isShapeResolved) return;
if (state.getFluidState().isEmpty()) {
noCollision = state.getCollisionShape(level, pos).isEmpty();
occludeFaces = new boolean[6];
if (state.canOcclude()) {
for (Direction dir : Direction.values()) {
// Note: isEmpty() isn't quite correct... best would be a isFull() or something...
occludeFaces[McObjectConverter.Convert(dir).ordinal()]
= !state.getFaceOcclusionShape(level, pos, dir).isEmpty();
}
}
VoxelShape voxelShape = state.getShape(level, pos);
fullFaces = new boolean[6];
if (!voxelShape.isEmpty()) {
for (Direction dir : Direction.values()) {
VoxelShape faceShape = voxelShape.getFaceShape(dir);
AABB aabb = faceShape.bounds();
boolean xFull = aabb.minX <= 0.01 && aabb.maxX >= 0.99;
boolean yFull = aabb.minY <= 0.01 && aabb.maxY >= 0.99;
boolean zFull = aabb.minZ <= 0.01 && aabb.maxZ >= 0.99;
fullFaces[McObjectConverter.Convert(dir).ordinal()] =
(xFull || dir.getAxis().equals(Direction.Axis.X))
&& (yFull || dir.getAxis().equals(Direction.Axis.Y))
&& (zFull || dir.getAxis().equals(Direction.Axis.Z));
}
}
} else { // Liquid Block. Treat as full block
occludeFaces = new boolean[6];
Arrays.fill(occludeFaces, true);
fullFaces = new boolean[6];
Arrays.fill(fullFaces, true);
}
}
}
@@ -0,0 +1,136 @@
package com.seibel.lod.common.wrappers.chunk;
import java.util.Objects;
import com.seibel.lod.core.util.LevelPosUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
import com.seibel.lod.common.wrappers.block.BlockPosWrapper;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ChunkPos;
/**
* @author James Seibel
* @version 11-21-2021
*/
public class ChunkPosWrapper extends AbstractChunkPosWrapper
{
private final net.minecraft.world.level.ChunkPos chunkPos;
public ChunkPosWrapper()
{
this.chunkPos = new ChunkPos(0, 0);
}
public ChunkPosWrapper(BlockPos blockPos)
{
this.chunkPos = new ChunkPos(blockPos);
}
public ChunkPosWrapper(AbstractChunkPosWrapper newChunkPos)
{
this.chunkPos = ((ChunkPosWrapper) newChunkPos).chunkPos;
}
public ChunkPosWrapper(AbstractBlockPosWrapper blockPos)
{
this.chunkPos = new ChunkPos(((BlockPosWrapper) blockPos).getBlockPos());
}
public ChunkPosWrapper(int chunkX, int chunkZ)
{
this.chunkPos = new ChunkPos(chunkX, chunkZ);
}
public ChunkPosWrapper(long l) {
this.chunkPos = new ChunkPos(l);
}
public ChunkPosWrapper(ChunkPos pos)
{
this.chunkPos = pos;
}
@Override
public int getX()
{
return chunkPos.x;
}
@Override
public int getZ()
{
return chunkPos.z;
}
@Override
public int getMinBlockX()
{
return chunkPos.getMinBlockX();
}
@Override
public int getMinBlockZ()
{
return chunkPos.getMinBlockZ();
}
@Override
public int getRegionX()
{
return LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkPos.x, LodUtil.REGION_DETAIL_LEVEL);
}
@Override
public int getRegionZ()
{
return LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkPos.z, LodUtil.REGION_DETAIL_LEVEL);
}
@Override
public long getLong() {
return chunkPos.toLong();
}
public ChunkPos getChunkPos()
{
return chunkPos;
}
@Override
public boolean equals(Object o)
{
// If the object is compared with itself then return true
if (o == this) {
return true;
}
// Check if o is an instance of RegionPos or not
if (!(o instanceof ChunkPosWrapper)) {
return false;
}
ChunkPosWrapper c = (ChunkPosWrapper) o;
return c.chunkPos.equals(chunkPos);
}
@Override
public int hashCode()
{
return Objects.hash(chunkPos);
}
@Override
public AbstractBlockPosWrapper getWorldPosition()
{
// the parameter here is the y position
BlockPos blockPos = chunkPos.getMiddleBlockPosition(0);
return new BlockPosWrapper(blockPos.getX(), blockPos.getY(), blockPos.getZ());
}
}
@@ -1,51 +1,31 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.chunk;
import com.seibel.lod.common.wrappers.block.BlockStateWrapper;
import com.seibel.lod.core.pos.DhBlockPos;
import com.seibel.lod.core.pos.DhChunkPos;
import com.seibel.lod.common.wrappers.block.BlockDetailWrapper;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.util.LevelPosUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.lod.common.wrappers.WrapperUtil;
import com.seibel.lod.common.wrappers.block.BiomeWrapper;
import com.seibel.lod.common.wrappers.block.BlockDetailMap;
import com.seibel.lod.common.wrappers.world.BiomeWrapper;
import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.LightedWorldGenRegion;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import net.minecraft.core.BlockPos;
#if POST_MC_1_17_1
import net.minecraft.core.QuartPos;
#endif
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.LiquidBlockContainer;
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.levelgen.Heightmap;
import javax.annotation.Nullable;
/**
*
* @author James Seibel
@@ -54,36 +34,24 @@ import javax.annotation.Nullable;
public class ChunkWrapper implements IChunkWrapper
{
private final ChunkAccess chunk;
private final DhChunkPos chunkPos;
private final LevelReader lightSource;
private final ILevelWrapper wrappedLevel;
public ChunkWrapper(ChunkAccess chunk, LevelReader lightSource, @Nullable ILevelWrapper wrappedLevel)
public ChunkWrapper(ChunkAccess chunk, LevelReader lightSource)
{
this.chunk = chunk;
this.lightSource = lightSource;
this.wrappedLevel = wrappedLevel;
chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
}
@Override
public int getHeight(){
#if PRE_MC_1_17_1
return 255;
#else
return chunk.getHeight();
#endif
}
@Override
public int getMinBuildHeight()
{
#if PRE_MC_1_17_1
return 0;
#else
return chunk.getMinBuildHeight();
#endif
}
@Override
public int getMaxBuildHeight()
@@ -100,28 +68,39 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public IBiomeWrapper getBiome(int x, int y, int z)
{
//if (wrappedLevel != null) return wrappedLevel.getBiome(new DhBlockPos(x + getMinX(), y, z + getMinZ()));
#if PRE_MC_1_17_1
return BiomeWrapper.getBiomeWrapper(chunk.getBiomes().getNoiseBiome(
x >> 2, y >> 2, z >> 2));
#elif PRE_MC_1_18_1
return BiomeWrapper.getBiomeWrapper(chunk.getBiomes().getNoiseBiome(
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
#elif PRE_MC_1_18_2
#if MC_VERSION_1_18_2
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
#else //Now returns a Holder<Biome> instead of Biome
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
#endif
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)).value());
#elif MC_VERSION_1_18_1
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
#endif
}
@Override
public DhChunkPos getChunkPos() {
return chunkPos;
public IBlockDetailWrapper getBlockDetail(int x, int y, int z) {
BlockPos pos = new BlockPos(x,y,z);
BlockState blockState = chunk.getBlockState(pos);
IBlockDetailWrapper blockDetail = BlockDetailMap.getOrMakeBlockDetailCache(blockState, pos, lightSource);
return blockDetail == BlockDetailWrapper.NULL_BLOCK_DETAIL ? null : blockDetail;
}
@Override
public IBlockDetailWrapper getBlockDetailAtFace(int x, int y, int z, LodDirection dir) {
int fy = y+dir.getNormal().y;
if (fy < getMinBuildHeight() || fy > getMaxBuildHeight()) return null;
BlockPos pos = new BlockPos(x+dir.getNormal().x,fy,z+dir.getNormal().z);
BlockState blockState;
if (blockPosInsideChunk(x,y,z))
blockState = chunk.getBlockState(pos);
else {
blockState = lightSource.getBlockState(pos);
}
if (blockState == null || blockState.isAir()) return null;
IBlockDetailWrapper blockDetail = BlockDetailMap.getOrMakeBlockDetailCache(blockState, pos, lightSource);
return blockDetail == BlockDetailWrapper.NULL_BLOCK_DETAIL ? null : blockDetail;
}
public ChunkAccess getChunk() {
return chunk;
}
@@ -148,7 +127,7 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public int getMaxY(int x, int z) {
return chunk.getHeight(Heightmap.Types.WORLD_SURFACE, Math.floorMod(x, 16), Math.floorMod(z, 16));
return chunk.getHeight(Heightmap.Types.MOTION_BLOCKING, Math.floorMod(x, 16), Math.floorMod(z, 16));
}
@Override
@@ -175,26 +154,38 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public boolean isLightCorrect(){
#if PRE_MC_1_18_1
return true;
#else
//if (chunk instanceof LevelChunk) {
// return ((LevelChunk) chunk).isClientLightReady();
//}
//return true;
if (chunk instanceof LevelChunk) {
return ((LevelChunk) chunk).isClientLightReady();
}
return chunk.isLightCorrect();
#endif
}
public boolean isWaterLogged(int x, int y, int z)
{
BlockState blockState = chunk.getBlockState(new BlockPos(x,y,z));
//This type of block is always in water
return (!(blockState.getBlock() instanceof LiquidBlockContainer) && (blockState.getBlock() instanceof SimpleWaterloggedBlock))
&& (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED));
}
@Override
public int getEmittedBrightness(int x, int y, int z)
{
return chunk.getLightEmission(new BlockPos(x,y,z));
}
@Override
public int getBlockLight(int x, int y, int z) {
if (lightSource == null) return -1;
return lightSource.getBrightness(LightLayer.BLOCK, new BlockPos(x + getMinX(),y,z + getMinZ()));
return lightSource.getBrightness(LightLayer.BLOCK, new BlockPos(x,y,z));
}
@Override
public int getSkyLight(int x, int y, int z) {
if (lightSource == null) return -1;
return lightSource.getBrightness(LightLayer.SKY, new BlockPos(x + getMinX(),y,z + getMinZ()));
return lightSource.getBrightness(LightLayer.SKY, new BlockPos(x,y,z));
}
@Override
@@ -203,7 +194,7 @@ public class ChunkWrapper implements IChunkWrapper
for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) {
if (dx==0 && dz==0) continue;
if (lightSource.getChunk(dx+chunk.getPos().x, dz+chunk.getPos().z, ChunkStatus.BIOMES, false) == null) return false;
if (lightSource.getChunk(dx+getChunkPosX(), dz+getChunkPosZ(), ChunkStatus.BIOMES, false) == null) return false;
}
}
return true;
@@ -213,20 +204,5 @@ public class ChunkWrapper implements IChunkWrapper
{
return lightSource;
}
@Override
public String toString() {
return chunk.getClass().getSimpleName() + chunk.getPos();
}
@Override
public IBlockStateWrapper getBlockState(int x, int y, int z) {
//if (wrappedLevel != null) return wrappedLevel.getBlockState(new DhBlockPos(x + getMinX(), y, z + getMinZ()));
return BlockStateWrapper.fromBlockState(chunk.getBlockState(new BlockPos(x,y,z)));
}
@Override
public boolean isStillValid() {
return wrappedLevel == null || wrappedLevel.tryGetChunk(chunkPos) == this;
}
}
@@ -0,0 +1,762 @@
package com.seibel.lod.common.wrappers.config;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
// Logger (for debug stuff)
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
// Uses https://github.com/TheElectronWill/night-config for toml (only for Fabric since Forge already includes this)
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
// Gets info from our own mod
import com.seibel.lod.common.LodCommonMain;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.config.*;
// Minecraft imports
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiComponent;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.client.resources.language.I18n; // translation
import net.minecraft.client.gui.narration.NarratableEntry; // Remove in 1.16
/**
* Based upon TinyConfig
* https://github.com/Minenash/TinyConfig
*
* This config should work for both Fabric and Forge as long as you use Mojang mappings
*
* Credits to Motschen
*
* @author coolGi2007
* @version 1-14-2022
*/
@SuppressWarnings("unchecked")
public abstract class ConfigGui
{
/*
TODO list
Fix floats not working
Make a wiki
Make it so you can enable and disable buttons from showing
Make min and max not final
Move the ConfigScreenConfigs class to the config class that extends this
*/
/*
List of hacky things that are done that should be done properly
The buttons that don't show are still loaded but just not rendered
The screen with is set to double so the scroll bar doesn't show
*/
private static final Pattern INTEGER_ONLY_REGEX = Pattern.compile("(-?[0-9]*)");
private static final Pattern DECIMAL_ONLY_REGEX = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
private static final List<EntryInfo> entries = new ArrayList<>();
public static final Map<String,EntryInfo> entryMap = new HashMap<>();
// Change these to your own mod
private static final String MOD_NAME = ModInfo.NAME; // For file saving and identifying
private static final String MOD_NAME_READABLE = ModInfo.READABLE_NAME; // For logs
// private static final Logger LOGGER = ApiShared.LOGGER; // For logs
private static final Logger LOGGER = LogManager.getLogger(ModInfo.NAME); // For logs (this inits before ClientAPI so this is a temp fix)
//==============//
// Initializers //
//==============//
private static class ConfigScreenConfigs
{
// This contains all the configs for the configs
public static final int SpaceFromRightScreen = 10;
public static final int ButtonWidthSpacing = 5;
public static final int ResetButtonWidth = 40;
}
public static class EntryInfo<T>
{
Field field;
Object widget;
int width = 0;
int max;
Map.Entry<EditBox, Component> error;
Object defaultValue;
Object value;
String tempValue;
boolean inLimits = true;
TranslatableComponent name;
int index;
/** Hides the button */
boolean hideOption = false;
/** This asks if it is a button to goto a new screen */
boolean screenButton = false;
/** This is only called if button is true */
String gotoScreen = "";
String category;
Class<T> varClass;
@Deprecated
boolean fileComment = false;
}
private static Path configFilePath;
public static void init(Class<?> config)
{
Minecraft mc = Minecraft.getInstance();
configFilePath = mc.gameDirectory.toPath().resolve("config").resolve(MOD_NAME + ".toml");
initNestedClass(config, "");
for (EntryInfo info : entries) {
if (info.field.isAnnotationPresent(ConfigAnnotations.Entry.class)) {
try {
info.value = info.field.get(null);
info.tempValue = info.value.toString();
} catch (IllegalAccessException ignored) {
}
}
}
loadFromFile();
}
private static void initNestedClass(Class<?> config, String category)
{
for (Field field : config.getFields())
{
EntryInfo info = new EntryInfo();
if (field.isAnnotationPresent(ConfigAnnotations.Entry.class) || field.isAnnotationPresent(ConfigAnnotations.Comment.class) || field.isAnnotationPresent(ConfigAnnotations.ScreenEntry.class))
{
// If putting in your own mod then put your own check for server sided
info.category = category;
if (!LodCommonMain.serverSided)
initClient(field, info, category);
}
if (field.isAnnotationPresent(ConfigAnnotations.Entry.class))
{
entryMap.put((!category.isEmpty() ? category + "." : "") + field.getName(), info);
info.varClass = field.getType();
try
{
info.defaultValue = field.get(null);
}
catch (IllegalAccessException ignored) {}
}
if (field.isAnnotationPresent(ConfigAnnotations.ScreenEntry.class))
initNestedClass(field.getType(), (!category.isEmpty() ? category + "." : "") + field.getName());
// File comment (WILL BE REMOVED SOON)
if (field.isAnnotationPresent(ConfigAnnotations.FileComment.class)) {
entryMap.put((!category.isEmpty() ? category + "." : "") + field.getName(), info);
info.fileComment = true;
try
{
info.value = info.defaultValue = field.get(null);
}
catch (IllegalAccessException ignored) {}
}
info.field = field;
}
}
/** This adds the buttons to the queue to be rendered */
private static void initClient(Field field, EntryInfo info, String category)
{
Class<?> fieldClass = field.getType();
ConfigAnnotations.Entry entry = field.getAnnotation(ConfigAnnotations.Entry.class);
ConfigAnnotations.ScreenEntry screenEntry = field.getAnnotation(ConfigAnnotations.ScreenEntry.class);
if (entry != null)
info.width = entry.width();
else if (screenEntry != null)
info.width = screenEntry.width();
if (entry != null)
{
if (!entry.name().equals(""))
info.name = new TranslatableComponent(entry.name());
if (fieldClass == int.class)
{
// For int
textField(info, Integer::parseInt, INTEGER_ONLY_REGEX, entry.minValue(), entry.maxValue(), true);
}
else if (fieldClass == double.class)
{
// For double
textField(info, Double::parseDouble, DECIMAL_ONLY_REGEX, entry.minValue(), entry.maxValue(), false);
}
else if (fieldClass == String.class || fieldClass == List.class)
{
// For string or list
info.max = entry.maxValue() == Double.MAX_VALUE ? Integer.MAX_VALUE : (int) entry.maxValue();
textField(info, String::length, null, Math.min(entry.minValue(), 0), Math.max(entry.maxValue(), 1), true);
}
else if (fieldClass == boolean.class)
{
// For boolean
Function<Object, Component> func = value -> new TextComponent((Boolean) value ? "True" : "False").withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
info.widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
info.value = !(Boolean) info.value;
button.setMessage(func.apply(info.value));
}, func);
}
else if (fieldClass.isEnum())
{
// For enum
List<?> values = Arrays.asList(field.getType().getEnumConstants());
Function<Object, Component> func = value -> new TranslatableComponent(MOD_NAME + ".config." + "enum." + fieldClass.getSimpleName() + "." + info.value.toString());
info.widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
int index = values.indexOf(info.value) + 1;
info.value = values.get(index >= values.size() ? 0 : index);
button.setMessage(func.apply(info.value));
}, func);
}
}
else if (screenEntry != null)
{
if (!screenEntry.name().equals(""))
info.name = new TranslatableComponent(screenEntry.name());
info.screenButton = true;
info.gotoScreen = (!info.category.isEmpty() ? info.category + "." : "") + field.getName();
}
entries.add(info);
}
/** creates a text field */
private static void textField(EntryInfo info, Function<String, Number> func, Pattern pattern, double minValue, double maxValue, boolean cast)
{
boolean isNumber = pattern != null;
info.widget = (BiFunction<EditBox, Button, Predicate<String>>) (editBox, button) -> stringValue ->
{
stringValue = stringValue.trim();
if (!(stringValue.isEmpty() || !isNumber || pattern.matcher(stringValue).matches()))
return false;
Number value = 0;
boolean inLimits = false;
info.error = null;
if (isNumber && !stringValue.isEmpty() && !stringValue.equals("-") && !stringValue.equals("."))
{
value = func.apply(stringValue);
inLimits = value.doubleValue() >= minValue && value.doubleValue() <= maxValue;
info.error = inLimits ? null : new AbstractMap.SimpleEntry<>(editBox, new TextComponent(value.doubleValue() < minValue ?
"§cMinimum " + "length" + (cast ? " is " + (int) minValue : " is " + minValue) :
"§cMaximum " + "length" + (cast ? " is " + (int) maxValue : " is " + maxValue)));
}
info.tempValue = stringValue;
editBox.setTextColor(inLimits ? 0xFFFFFFFF : 0xFFFF7777);
info.inLimits = inLimits;
button.active = entries.stream().allMatch(e -> e.inLimits);
if (inLimits && info.field.getType() != List.class)
{
info.value = value;
}
else if (inLimits)
{
if (((List<String>) info.value).size() == info.index)
((List<String>) info.value).add("");
((List<String>) info.value).set(info.index, Arrays.stream(info.tempValue.replace("[", "").replace("]", "").split(", ")).collect(Collectors.toList()).get(0));
}
return true;
};
}
//===============//
// File Handling //
//===============//
/** Grabs what is in the config and puts it in modid.toml */
public static void saveToFile()
{
CommentedFileConfig config = CommentedFileConfig.builder(configFilePath.toFile()).build();
// First try to create a config file
try {
if (!Files.exists(configFilePath))
Files.createFile(configFilePath);
}
catch (Exception e) {
LOGGER.info("Failed creating config file for " + MOD_NAME_READABLE + " at the path [" + configFilePath.toString() + "].");
e.printStackTrace();
}
loadFileWithErrorCheck(config);
// Just put this here for the future
config.setComment("_Version", " DONT TOUCH THIS, IF YOU DO THEN CONFIG FILE WOULD BREAK");
config.set("_Versions", ModInfo.VERSION);
for (EntryInfo info : entries) {
if (info.field.isAnnotationPresent(ConfigAnnotations.Entry.class)) {
editSingleOption.saveOption(info, config);
if (editSingleOption.getEntry((info.category.isEmpty() ? "" : info.category + ".") + "_" + info.field.getName()) != null)
config.setComment((info.category.isEmpty() ? "" : info.category + ".") + info.field.getName(), String.valueOf(editSingleOption.getEntry((info.category.isEmpty() ? "" : info.category + ".") + "_" + info.field.getName()).defaultValue));
}
}
config.save();
config.close();
}
/**
* Grabs what is in modid.toml and puts it into the config
* If the file doesn't exist then it runs saveToFile
*/
public static void loadFromFile()
{
CommentedFileConfig config = CommentedFileConfig.builder(configFilePath.toFile()).autosave().build();
// First checks if the config file was already made
if (!Files.exists(configFilePath)) {
LOGGER.info("Config file not found for " + MOD_NAME_READABLE + ". Creating config...");
saveToFile();
return;
}
loadFileWithErrorCheck(config);
// Just put this here for the future
config.setComment("_Version", " DONT TOUCH THIS, IF YOU DO THEN CONFIG FILE WOULD BREAK");
config.set("_Versions", ModInfo.VERSION);
// Puts everything into its variable
for (EntryInfo info : entries) {
if (info.field.isAnnotationPresent(ConfigAnnotations.Entry.class)) {
editSingleOption.loadOption(info, config);
// File comments (WILL REMOVE SOON)
if (editSingleOption.getEntry((info.category.isEmpty() ? "" : info.category + ".") + "_" + info.field.getName()) != null)
config.setComment((info.category.isEmpty() ? "" : info.category + ".") + info.field.getName(), String.valueOf(editSingleOption.getEntry((info.category.isEmpty() ? "" : info.category + ".") + "_" + info.field.getName()).defaultValue));
}
}
config.close();
}
public static class editSingleOption {
/** Get the entry info of an item using its string name */
public static EntryInfo getEntry(String name)
{
return entryMap.get(name);
}
/** Save a single item using its string name */
public static void saveOption(String name)
{
saveOption(entryMap.get(name));
}
/** Saves a single item using entry info */
public static void saveOption(EntryInfo info)
{
CommentedFileConfig config = CommentedFileConfig.builder(configFilePath.toFile()).autosave().build();
loadFileWithErrorCheck(config);
saveOption(info, config);
config.close();
}
/** Saves a single item using its entry info and its config builder */
public static void saveOption(EntryInfo info, CommentedFileConfig config)
{
config.set((info.category.isEmpty() ? "" : info.category + ".") + info.field.getName(), info.value);
}
/** Load a single item using its string name */
public static void loadOption(String name)
{
loadOption(entryMap.get(name));
}
/** Load a single item using entry info */
public static void loadOption(EntryInfo info)
{
CommentedFileConfig config = CommentedFileConfig.builder(configFilePath.toFile()).autosave().build();
loadFileWithErrorCheck(config);
loadOption(info, config);
config.close();
}
/** Loads a single item using its entry info and its config builder */
public static void loadOption(EntryInfo info, CommentedFileConfig config)
{
String itemPath = (info.category.isEmpty() ? "" : info.category + ".") + info.field.getName();
if (config.contains(itemPath)) {
if (info.field.getType().isEnum())
info.value = config.getEnum(itemPath, info.varClass);
else
info.value = config.get(itemPath);
} else
config.set(itemPath, info.value);
try {
info.field.set(null, info.value);
} catch (IllegalAccessException ignored) {
}
}
}
/** Dose config.load(); but with error checking to avoid crashes */
public static void loadFileWithErrorCheck(CommentedFileConfig config) {
try {
config.load();
} catch (Exception e) {
LOGGER.info("Error loading config for " + MOD_NAME_READABLE + " at the path [" + configFilePath.toString() + "].");
LOGGER.info("Creating a new config...");
try {
Files.deleteIfExists(configFilePath);
saveToFile();
} catch (Exception f) {
LOGGER.info("Failed creating config file for " + MOD_NAME_READABLE + " at the path [" + configFilePath.toString() + "].");
f.printStackTrace();
}
}
}
//==============//
// GUI handling //
//==============//
public static Screen getScreen(Screen parent, String category)
{
return new ConfigScreen(parent, category);
}
private static class ConfigScreen extends Screen
{
protected ConfigScreen(Screen parent, String category)
{
super(new TranslatableComponent(
I18n.exists(MOD_NAME + ".config" + (category.isEmpty()? "." + category : "") + ".title") ?
MOD_NAME + ".config.title" :
MOD_NAME + ".config" + (category.isEmpty() ? "" : "." + category) + ".title")
);
this.parent = parent;
this.category = category;
this.translationPrefix = MOD_NAME + ".config.";
}
private final String translationPrefix;
private final Screen parent;
private final String category;
private ConfigListWidget list;
private boolean reload = false;
// Real Time config update //
@Override
public void tick()
{
super.tick();
}
/** When you close it, it goes to the previous screen and saves */
@Override
public void onClose()
{
saveToFile();
Objects.requireNonNull(minecraft).setScreen(this.parent);
}
@Override
protected void init()
{
super.init();
if (!reload)
loadFromFile();
// addRenderableWidget in 1.17 and over
// addButton in 1.16 and below
this.addRenderableWidget(new Button(this.width / 2 - 154, this.height - 28, 150, 20, CommonComponents.GUI_CANCEL, button -> {
loadFromFile();
Objects.requireNonNull(minecraft).setScreen(parent);
}));
Button done = this.addRenderableWidget(new Button(this.width / 2 + 4, this.height - 28, 150, 20, CommonComponents.GUI_DONE, (button) -> {
saveToFile();
Objects.requireNonNull(minecraft).setScreen(parent);
}));
this.list = new ConfigListWidget(this.minecraft, this.width * 2, this.height, 32, this.height - 32, 25);
if (this.minecraft != null && this.minecraft.level != null)
this.list.setRenderBackground(false);
this.addWidget(this.list);
for (EntryInfo info : entries)
{
if (info.category.matches(category) && !info.hideOption)
{
TranslatableComponent name = (info.name == null ? new TranslatableComponent(translationPrefix + (!info.category.isEmpty() ? info.category + "." : "") + info.field.getName()) : info.name);
Button resetButton = new Button(this.width - ConfigScreenConfigs.SpaceFromRightScreen - info.width - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth, 0, ConfigScreenConfigs.ResetButtonWidth, 20, new TextComponent("Reset").withStyle(ChatFormatting.RED), (button -> {
info.value = info.defaultValue;
info.tempValue = info.defaultValue.toString();
info.index = 0;
this.reload = true;
Objects.requireNonNull(minecraft).setScreen(this);
}));
if (info.widget instanceof Map.Entry)
{
Map.Entry<Button.OnPress, Function<Object, Component>> widget = (Map.Entry<Button.OnPress, Function<Object, Component>>) info.widget;
if (info.field.getType().isEnum())
widget.setValue(value -> new TranslatableComponent(translationPrefix + "enum." + info.field.getType().getSimpleName() + "." + info.value.toString()));
this.list.addButton(new Button(this.width - info.width - ConfigScreenConfigs.SpaceFromRightScreen, 0, info.width, 20, widget.getValue().apply(info.value), widget.getKey()), resetButton, null, name);
}
else if (info.field.getType() == List.class)
{
if (!reload)
info.index = 0;
EditBox widget = new EditBox(font, this.width - info.width - ConfigScreenConfigs.SpaceFromRightScreen, 0, info.width, 20, null);
widget.setMaxLength(info.width);
if (info.index < ((List<String>) info.value).size())
widget.insertText((String.valueOf(((List<String>) info.value).get(info.index))));
else
widget.insertText("");
Predicate<String> processor = ((BiFunction<EditBox, Button, Predicate<String>>) info.widget).apply(widget, done);
widget.setFilter(processor);
resetButton.setWidth(20);
resetButton.setMessage(new TextComponent("R").withStyle(ChatFormatting.RED));
Button cycleButton = new Button(this.width - 185, 0, 20, 20, new TextComponent(String.valueOf(info.index)).withStyle(ChatFormatting.GOLD), (button -> {
((List<String>) info.value).remove("");
this.reload = true;
info.index = info.index + 1;
if (info.index > ((List<String>) info.value).size())
info.index = 0;
Objects.requireNonNull(minecraft).setScreen(this);
}));
this.list.addButton(widget, resetButton, cycleButton, name);
}
else if (info.widget != null)
{
EditBox widget = new EditBox(font, this.width - info.width - ConfigScreenConfigs.SpaceFromRightScreen + 2, 0, info.width - 4, 20, null);
widget.setMaxLength(info.width);
widget.insertText(String.valueOf(info.value));
Predicate<String> processor = ((BiFunction<EditBox, Button, Predicate<String>>) info.widget).apply(widget, done);
widget.setFilter(processor);
this.list.addButton(widget, resetButton, null, name);
}
else if (info.screenButton)
{
Button widget = new Button(this.width / 2 - info.width, this.height - 28, info.width * 2, 20, name, (button -> {
saveToFile();
Objects.requireNonNull(minecraft).setScreen(ConfigGui.getScreen(this, info.gotoScreen));
}));
this.list.addButton(widget, null, null, null);
}
else if (!info.fileComment)
{
this.list.addButton(null, null, null, name);
}
}
}
}
@Override
public void render(PoseStack matrices, int mouseX, int mouseY, float delta)
{
this.renderBackground(matrices); // Renders background
this.list.render(matrices, mouseX, mouseY, delta); // Render buttons
drawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
// Render the tooltip only if it can find a tooltip in the language file
for (EntryInfo info : entries) {
if (info.category.matches(category) && !info.hideOption) {
if (list.getHoveredButton(mouseX,mouseY).isPresent()) {
AbstractWidget buttonWidget = list.getHoveredButton(mouseX,mouseY).get();
Component text = ButtonEntry.buttonsWithText.get(buttonWidget);
TranslatableComponent name = new TranslatableComponent(this.translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.field.getName());
String key = translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.field.getName() + ".@tooltip";
if (info.error != null && text.equals(name)) renderTooltip(matrices, (Component) info.error.getValue(), mouseX, mouseY);
else if (I18n.exists(key) && (text != null && text.equals(name))) {
List<Component> list = new ArrayList<>();
for (String str : I18n.get(key).split("\n"))
list.add(new TextComponent(str));
renderComponentTooltip(matrices, list, mouseX, mouseY);
}
}
}
}
super.render(matrices, mouseX, mouseY, delta);
}
}
public static class ConfigListWidget extends ContainerObjectSelectionList<ButtonEntry>
{
Font textRenderer;
public ConfigListWidget(Minecraft minecraftClient, int i, int j, int k, int l, int m)
{
super(minecraftClient, i, j, k, l, m);
this.centerListVertically = false;
textRenderer = minecraftClient.font;
}
public void addButton(AbstractWidget button, AbstractWidget resetButton, AbstractWidget indexButton, Component text)
{
this.addEntry(ButtonEntry.create(button, text, resetButton, indexButton));
}
@Override
public int getRowWidth()
{
return 10000;
}
public Optional<AbstractWidget> getHoveredButton(double mouseX, double mouseY)
{
for (ButtonEntry buttonEntry : this.children())
{
if (buttonEntry.button != null && buttonEntry.button.isMouseOver(mouseX, mouseY))
{
return Optional.of(buttonEntry.button);
}
}
return Optional.empty();
}
}
public static class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry>
{
private static final Font textRenderer = Minecraft.getInstance().font;
public final AbstractWidget button;
private final AbstractWidget resetButton;
private final AbstractWidget indexButton;
private final Component text;
private final List<AbstractWidget> children = new ArrayList<>();
public static final Map<AbstractWidget, Component> buttonsWithText = new HashMap<>();
private ButtonEntry(AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton)
{
buttonsWithText.put(button, text);
this.button = button;
this.resetButton = resetButton;
this.text = text;
this.indexButton = indexButton;
if (button != null)
children.add(button);
if (resetButton != null)
children.add(resetButton);
if (indexButton != null)
children.add(indexButton);
}
public static ButtonEntry create(AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton)
{
return new ButtonEntry(button, text, resetButton, indexButton);
}
@Override
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
{
if (button != null)
{
button.y = y;
button.render(matrices, mouseX, mouseY, tickDelta);
}
if (resetButton != null)
{
resetButton.y = y;
resetButton.render(matrices, mouseX, mouseY, tickDelta);
}
if (indexButton != null)
{
indexButton.y = y;
indexButton.render(matrices, mouseX, mouseY, tickDelta);
}
if (text != null && (!text.getString().contains("spacer") || button != null))
GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF);
}
@Override
public List<? extends GuiEventListener> children()
{
return children;
}
// Only for 1.17 and over
// Remove in 1.16 and below
@Override
public List<? extends NarratableEntry> narratables()
{
return children;
}
}
}
@@ -0,0 +1,953 @@
package com.seibel.lod.common.wrappers.config;
import com.seibel.lod.core.enums.config.*;
import com.seibel.lod.core.enums.rendering.*;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.common.Config;
/**
* This holds the config defaults and setters/getters
* that should be hooked into the host mod loader (Fabric, Forge, etc.).
*
* @author James Seibel
* @version 11-16-2021
*/
public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
{
public static final LodConfigWrapperSingleton INSTANCE = new LodConfigWrapperSingleton();
private static final Client client = new Client();
@Override
public IClient client()
{
return client;
}
public static class Client implements IClient
{
public final IGraphics graphics;
public final IWorldGenerator worldGenerator;
public final IMultiplayer multiplayer;
public final IAdvanced advanced;
@Override
public IGraphics graphics()
{
return graphics;
}
@Override
public IWorldGenerator worldGenerator()
{
return worldGenerator;
}
@Override
public IMultiplayer multiplayer() {
return multiplayer;
}
@Override
public IAdvanced advanced()
{
return advanced;
}
@Override
public boolean getOptionsButton()
{
return Config.optionsButton;
}
@Override
public void setOptionsButton(boolean newOptionsButton)
{
ConfigGui.editSingleOption.getEntry("optionsButton").value = newOptionsButton;
ConfigGui.editSingleOption.saveOption("optionsButton");
}
//================//
// Client Configs //
//================//
public Client()
{
graphics = new Graphics();
worldGenerator = new WorldGenerator();
multiplayer = new Multiplayer();
advanced = new Advanced();
}
//==================//
// Graphics Configs //
//==================//
public static class Graphics implements IGraphics
{
public final IQuality quality;
public final IFogQuality fogQuality;
public final IAdvancedGraphics advancedGraphics;
@Override
public IQuality quality()
{
return quality;
}
@Override
public IFogQuality fogQuality()
{
return fogQuality;
}
@Override
public IAdvancedGraphics advancedGraphics()
{
return advancedGraphics;
}
Graphics()
{
quality = new Quality();
fogQuality = new FogQuality();
advancedGraphics = new AdvancedGraphics();
}
public static class Quality implements IQuality
{
@Override
public HorizontalResolution getDrawResolution()
{
return Config.Client.Graphics.Quality.drawResolution;
}
@Override
public void setDrawResolution(HorizontalResolution newHorizontalResolution)
{
ConfigGui.editSingleOption.getEntry("client.graphics.quality.drawResolution").value = newHorizontalResolution;
ConfigGui.editSingleOption.saveOption("client.graphics.quality.drawResolution");
}
@Override
public int getLodChunkRenderDistance()
{
return Config.Client.Graphics.Quality.lodChunkRenderDistance;
}
@Override
public void setLodChunkRenderDistance(int newLodChunkRenderDistance)
{
ConfigGui.editSingleOption.getEntry("client.graphics.quality.lodChunkRenderDistance").value = newLodChunkRenderDistance;
ConfigGui.editSingleOption.saveOption("client.graphics.quality.lodChunkRenderDistance");
}
@Override
public VerticalQuality getVerticalQuality()
{
return Config.Client.Graphics.Quality.verticalQuality;
}
@Override
public void setVerticalQuality(VerticalQuality newVerticalQuality)
{
ConfigGui.editSingleOption.getEntry("client.graphics.quality.verticalQuality").value = newVerticalQuality;
ConfigGui.editSingleOption.saveOption("client.graphics.quality.verticalQuality");
}
@Override
public int getHorizontalScale()
{
return Config.Client.Graphics.Quality.horizontalScale;
}
@Override
public void setHorizontalScale(int newHorizontalScale)
{
ConfigGui.editSingleOption.getEntry("client.graphics.quality.horizontalScale").value = newHorizontalScale;
ConfigGui.editSingleOption.saveOption("client.graphics.quality.horizontalScale");
}
@Override
public HorizontalQuality getHorizontalQuality()
{
return Config.Client.Graphics.Quality.horizontalQuality;
}
@Override
public void setHorizontalQuality(HorizontalQuality newHorizontalQuality)
{
ConfigGui.editSingleOption.getEntry("client.graphics.quality.horizontalQuality").value = newHorizontalQuality;
ConfigGui.editSingleOption.saveOption("client.graphics.quality.horizontalQuality");
}
@Override
public DropoffQuality getDropoffQuality() {
return Config.Client.Graphics.Quality.dropoffQuality;
}
@Override
public void setDropoffQuality(DropoffQuality newDropoffQuality) {
ConfigGui.editSingleOption.getEntry("client.graphics.quality.dropoffQuality").value = newDropoffQuality;
ConfigGui.editSingleOption.saveOption("client.graphics.quality.dropoffQuality");
}
@Override
public int getLodBiomeBlending() {
return Config.Client.Graphics.Quality.lodBiomeBlending;
}
@Override
public void setLodBiomeBlending(int newLodBiomeBlending) {
ConfigGui.editSingleOption.getEntry("client.graphics.quality.lodBiomeBlending").value = newLodBiomeBlending;
ConfigGui.editSingleOption.saveOption("client.graphics.quality.lodBiomeBlending");
}
}
public static class FogQuality implements IFogQuality
{
public final IAdvancedFog advancedFog;
FogQuality()
{
advancedFog = new AdvancedFog();
}
@Override
public FogDistance getFogDistance()
{
return Config.Client.Graphics.FogQuality.fogDistance;
}
@Override
public void setFogDistance(FogDistance newFogDistance)
{
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.fogDistance").value = newFogDistance;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.fogDistance");
}
@Override
public FogDrawMode getFogDrawMode()
{
return Config.Client.Graphics.FogQuality.fogDrawMode;
}
@Override
public void setFogDrawMode(FogDrawMode setFogDrawMode)
{
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.fogDrawMode").value = setFogDrawMode;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.fogDrawMode");
}
@Override
public FogColorMode getFogColorMode()
{
return Config.Client.Graphics.FogQuality.fogColorMode;
}
@Override
public void setFogColorMode(FogColorMode newFogColorMode)
{
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.fogColorMode").value = newFogColorMode;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.fogColorMode");
}
@Override
public boolean getDisableVanillaFog()
{
return Config.Client.Graphics.FogQuality.disableVanillaFog;
}
@Override
public void setDisableVanillaFog(boolean newDisableVanillaFog)
{
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.disableVanillaFog").value = newDisableVanillaFog;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.disableVanillaFog");
}
@Override
public IAdvancedFog advancedFog() {
return advancedFog;
}
public static class AdvancedFog implements IAdvancedFog {
public final IHeightFog heightFog;
public AdvancedFog() {
heightFog = new HeightFog();
}
@Override
public double getFarFogStart() {
return Config.Client.Graphics.FogQuality.AdvancedFog.farFogStart;
}
@Override
public double getFarFogEnd() {
return Config.Client.Graphics.FogQuality.AdvancedFog.farFogEnd;
}
@Override
public double getFarFogMin() {
return Config.Client.Graphics.FogQuality.AdvancedFog.farFogMin;
}
@Override
public double getFarFogMax() {
return Config.Client.Graphics.FogQuality.AdvancedFog.farFogMax;
}
@Override
public FogSetting.FogType getFarFogType() {
return Config.Client.Graphics.FogQuality.AdvancedFog.farFogType;
}
@Override
public double getFarFogDensity() {
return Config.Client.Graphics.FogQuality.AdvancedFog.farFogDensity;
}
@Override
public void setFarFogStart(double newFarFogStart) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.farFogStart").value = newFarFogStart;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.farFogStart");
}
@Override
public void setFarFogEnd(double newFarFogEnd) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.farFogEnd").value = newFarFogEnd;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.farFogEnd");
}
@Override
public void setFarFogMin(double newFarFogMin) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.farFogMin").value = newFarFogMin;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.farFogMin");
}
@Override
public void setFarFogMax(double newFarFogMax) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.farFogMax").value = newFarFogMax;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.farFogMax");
}
@Override
public void setFarFogType(FogSetting.FogType newFarFogType) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.farFogType").value = newFarFogType;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.farFogType");
}
@Override
public void setFarFogDensity(double newFarFogDensity) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.farFogDensity").value = newFarFogDensity;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.farFogDensity");
}
@Override
public IHeightFog heightFog() {
return heightFog;
}
public static class HeightFog implements IHeightFog {
@Override
public HeightFogMixMode getHeightFogMixMode() {
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogMixMode;
}
@Override
public HeightFogMode getHeightFogMode() {
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogMode;
}
@Override
public double getHeightFogHeight() {
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogHeight;
}
@Override
public double getHeightFogStart() {
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogStart;
}
@Override
public double getHeightFogEnd() {
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogEnd;
}
@Override
public double getHeightFogMin() {
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogMin;
}
@Override
public double getHeightFogMax() {
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogMax;
}
@Override
public FogSetting.FogType getHeightFogType() {
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogType;
}
@Override
public double getHeightFogDensity() {
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogDensity;
}
@Override
public void setHeightFogMixMode(HeightFogMixMode newHeightFogMixMode) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogMixMode").value = newHeightFogMixMode;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogMixMode");
}
@Override
public void setHeightFogMode(HeightFogMode newHeightFogMode) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogMode").value = newHeightFogMode;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogMode");
}
@Override
public void setHeightFogHeight(double newHeightFogHeight) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogHeight").value = newHeightFogHeight;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogHeight");
}
@Override
public void setHeightFogStart(double newHeightFogStart) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogStart").value = newHeightFogStart;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogStart");
}
@Override
public void setHeightFogEnd(double newHeightFogEnd) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogEnd").value = newHeightFogEnd;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogEnd");
}
@Override
public void setHeightFogMin(double newHeightFogMin) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogMin").value = newHeightFogMin;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogMin");
}
@Override
public void setHeightFogMax(double newHeightFogMax) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogMax").value = newHeightFogMax;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogMax");
}
@Override
public void setHeightFogType(FogSetting.FogType newHeightFogType) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogType").value = newHeightFogType;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogType");
}
@Override
public void setHeightFogDensity(double newHeightFogDensity) {
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogDensity").value = newHeightFogDensity;
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogDensity");
}
}
}
}
public static class AdvancedGraphics implements IAdvancedGraphics
{
@Override
public boolean getDisableDirectionalCulling()
{
return Config.Client.Graphics.AdvancedGraphics.disableDirectionalCulling;
}
@Override
public void setDisableDirectionalCulling(boolean newDisableDirectionalCulling)
{
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.disableDirectionalCulling").value = newDisableDirectionalCulling;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.disableDirectionalCulling");
}
@Override
public VanillaOverdraw getVanillaOverdraw()
{
return Config.Client.Graphics.AdvancedGraphics.vanillaOverdraw;
}
@Override
public void setVanillaOverdraw(VanillaOverdraw newVanillaOverdraw)
{
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.vanillaOverdraw").value = newVanillaOverdraw;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.vanillaOverdraw");
}
@Override
public int getOverdrawOffset() {
return Config.Client.Graphics.AdvancedGraphics.overdrawOffset;
}
@Override
public void setOverdrawOffset(int newOverdrawOffset) {
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.overdrawOffset").value = newOverdrawOffset;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.overdrawOffset");
}
/*
@Override
public int getBacksideCullingRange()
{
return Config.Client.Graphics.AdvancedGraphics.backsideCullingRange;
}
@Override
public void setBacksideCullingRange(int newBacksideCullingRange)
{
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.backsideCullingRange").value = newBacksideCullingRange;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.backsideCullingRange");
}*/
@Override
public boolean getUseExtendedNearClipPlane()
{
return Config.Client.Graphics.AdvancedGraphics.useExtendedNearClipPlane;
}
@Override
public void setUseExtendedNearClipPlane(boolean newUseExtendedNearClipPlane)
{
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.useExtendedNearClipPlane").value = newUseExtendedNearClipPlane;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.useExtendedNearClipPlane");
}
@Override
public double getBrightnessMultiplier()
{
return Config.Client.Graphics.AdvancedGraphics.brightnessMultiplier;
}
@Override
public void setBrightnessMultiplier(double newBrightnessMultiplier)
{
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.brightnessMultiplier").value = newBrightnessMultiplier;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.brightnessMultiplier");
}
@Override
public double getSaturationMultiplier()
{
return Config.Client.Graphics.AdvancedGraphics.saturationMultiplier;
}
@Override
public void setSaturationMultiplier(double newSaturationMultiplier)
{
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.saturationMultiplier").value = newSaturationMultiplier;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.saturationMultiplier");
}
@Override
public boolean getEnableCaveCulling() {
return Config.Client.Graphics.AdvancedGraphics.enableCaveCulling;
}
@Override
public void setEnableCaveCulling(boolean newEnableCaveCulling) {
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.enableCaveCulling").value = newEnableCaveCulling;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.enableCaveCulling");
}
@Override
public int getCaveCullingHeight() {
return Config.Client.Graphics.AdvancedGraphics.caveCullingHeight;
}
@Override
public void setCaveCullingHeight(int newCaveCullingHeight) {
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.caveCullingHeight").value = newCaveCullingHeight;
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.caveCullingHeight");
}
}
}
//========================//
// WorldGenerator Configs //
//========================//
public static class WorldGenerator implements IWorldGenerator
{
@Override
public GenerationPriority getGenerationPriority()
{
return Config.Client.WorldGenerator.generationPriority;
}
@Override
public void setGenerationPriority(GenerationPriority newGenerationPriority)
{
ConfigGui.editSingleOption.getEntry("client.worldGenerator.generationPriority").value = newGenerationPriority;
ConfigGui.editSingleOption.saveOption("client.worldGenerator.generationPriority");
}
@Override
public DistanceGenerationMode getDistanceGenerationMode()
{
return Config.Client.WorldGenerator.distanceGenerationMode;
}
@Override
public void setDistanceGenerationMode(DistanceGenerationMode newDistanceGenerationMode)
{
ConfigGui.editSingleOption.getEntry("client.worldGenerator.distanceGenerationMode").value = newDistanceGenerationMode;
ConfigGui.editSingleOption.saveOption("client.worldGenerator.distanceGenerationMode");
}
/*
@Override
public boolean getAllowUnstableFeatureGeneration()
{
return Config.Client.WorldGenerator.allowUnstableFeatureGeneration;
}
@Override
public void setAllowUnstableFeatureGeneration(boolean newAllowUnstableFeatureGeneration)
{
ConfigGui.editSingleOption.getEntry("client.worldGenerator.allowUnstableFeatureGeneration").value = newAllowUnstableFeatureGeneration;
ConfigGui.editSingleOption.saveOption("client.worldGenerator.allowUnstableFeatureGeneration");
}*/
@Override
public BlocksToAvoid getBlocksToAvoid()
{
return Config.Client.WorldGenerator.blocksToAvoid;
}
@Override
public void setBlockToAvoid(BlocksToAvoid newBlockToAvoid)
{
ConfigGui.editSingleOption.getEntry("client.worldGenerator.blocksToAvoid").value = newBlockToAvoid;
ConfigGui.editSingleOption.saveOption("client.worldGenerator.blocksToAvoid");
}
@Override
public boolean getEnableDistantGeneration()
{
return (boolean) ConfigGui.editSingleOption.getEntry("client.worldGenerator.enableDistantGeneration").value;
}
@Override
public void setEnableDistantGeneration(boolean newEnableDistantGeneration)
{
ConfigGui.editSingleOption.getEntry("client.worldGenerator.enableDistantGeneration").value = newEnableDistantGeneration;
ConfigGui.editSingleOption.saveOption("client.worldGenerator.enableDistantGeneration");
}
@Override
public LightGenerationMode getLightGenerationMode()
{
return Config.Client.WorldGenerator.lightGenerationMode;
}
@Override
public void setLightGenerationMode(LightGenerationMode newLightGenerationMode)
{
ConfigGui.editSingleOption.getEntry("client.worldGenerator.lightGenerationMode").value = newLightGenerationMode;
ConfigGui.editSingleOption.saveOption("client.worldGenerator.lightGenerationMode");
}
}
//=====================//
// Multiplayer Configs //
//=====================//
public static class Multiplayer implements IMultiplayer
{
@Override
public ServerFolderNameMode getServerFolderNameMode()
{
return Config.Client.Multiplayer.serverFolderNameMode;
}
@Override
public void setServerFolderNameMode(ServerFolderNameMode newServerFolderNameMode)
{
ConfigGui.editSingleOption.getEntry("client.multiplayer.serverFolderNameMode").value = newServerFolderNameMode;
ConfigGui.editSingleOption.saveOption("client.multiplayer.serverFolderNameMode");
}
@Override
public double getMultiDimensionRequiredSimilarity()
{
return Config.Client.Multiplayer.multiDimensionRequiredSimilarity;
}
@Override
public void setMultiDimensionRequiredSimilarity(double newMultiDimensionMinimumSimilarityPercent)
{
ConfigGui.editSingleOption.getEntry("client.multiplayer.multiDimensionMinimumSimilarityPercent").value = newMultiDimensionMinimumSimilarityPercent;
ConfigGui.editSingleOption.saveOption("client.multiplayer.multiDimensionMinimumSimilarityPercent");
}
}
//============================//
// AdvancedModOptions Configs //
//============================//
public static class Advanced implements IAdvanced
{
public final IThreading threading;
public final IDebugging debugging;
public final IBuffers buffers;
@Override
public IThreading threading()
{
return threading;
}
@Override
public IDebugging debugging()
{
return debugging;
}
@Override
public IBuffers buffers()
{
return buffers;
}
public Advanced()
{
threading = new Threading();
debugging = new Debugging();
buffers = new Buffers();
}
public static class Threading implements IThreading
{
@Override
public int getNumberOfWorldGenerationThreads()
{
return Config.Client.Advanced.Threading.numberOfWorldGenerationThreads;
}
@Override
public void setNumberOfWorldGenerationThreads(int newNumberOfWorldGenerationThreads)
{
ConfigGui.editSingleOption.getEntry("client.advanced.threading.numberOfWorldGenerationThreads").value = newNumberOfWorldGenerationThreads;
ConfigGui.editSingleOption.saveOption("client.advanced.threading.numberOfWorldGenerationThreads");
}
@Override
public int getNumberOfBufferBuilderThreads()
{
return Config.Client.Advanced.Threading.numberOfBufferBuilderThreads;
}
@Override
public void setNumberOfBufferBuilderThreads(int newNumberOfWorldBuilderThreads)
{
ConfigGui.editSingleOption.getEntry("client.advanced.threading.numberOfBufferBuilderThreads").value = newNumberOfWorldBuilderThreads;
ConfigGui.editSingleOption.saveOption("client.advanced.threading.numberOfBufferBuilderThreads");
}
}
//===============//
// Debug Options //
//===============//
public static class Debugging implements IDebugging
{
public final IDebugSwitch debugSwitch;
@Override
public IDebugSwitch debugSwitch()
{
return debugSwitch;
}
/* RendererType:
* DEFAULT
* DEBUG
* DISABLED
* */
@Override
public RendererType getRendererType() {
return (RendererType) ConfigGui.editSingleOption.getEntry("client.advanced.debugging.rendererType").value;
}
@Override
public void setRendererType(RendererType newRenderType) {
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.rendererType").value = newRenderType;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.rendererType");
}
@Override
public DebugMode getDebugMode()
{
return (DebugMode) ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugMode").value;
}
@Override
public void setDebugMode(DebugMode newDebugMode)
{
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugMode").value = newDebugMode;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugMode");
}
@Override
public boolean getDebugKeybindingsEnabled()
{
return (boolean) ConfigGui.editSingleOption.getEntry("client.advanced.debugging.enableDebugKeybindings").value;
}
@Override
public void setDebugKeybindingsEnabled(boolean newEnableDebugKeybindings)
{
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.enableDebugKeybindings").value = newEnableDebugKeybindings;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.enableDebugKeybindings");
}
public Debugging()
{
debugSwitch = new DebugSwitch();
}
public static class DebugSwitch implements IDebugSwitch {
/* The logging switches available:
* WorldGenEvent
* WorldGenPerformance
* WorldGenLoadEvent
* LodBuilderEvent
* RendererBufferEvent
* RendererGLEvent
* FileReadWriteEvent
* FileSubDimEvent
* NetworkEvent //NOT IMPL YET
*/
@Override
public LoggerMode getLogWorldGenEvent() {
return (LoggerMode) ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logWorldGenEvent").value;
}
@Override
public void setLogWorldGenEvent(LoggerMode newLogWorldGenEvent) {
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logWorldGenEvent").value = newLogWorldGenEvent;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugSwitch.logWorldGenEvent");
}
@Override
public LoggerMode getLogWorldGenPerformance() {
return (LoggerMode) ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logWorldGenPerformance").value;
}
@Override
public void setLogWorldGenPerformance(LoggerMode newLogWorldGenPerformance) {
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logWorldGenPerformance").value = newLogWorldGenPerformance;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugSwitch.logWorldGenPerformance");
}
@Override
public LoggerMode getLogWorldGenLoadEvent() {
return (LoggerMode) ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logWorldGenLoadEvent").value;
}
@Override
public void setLogWorldGenLoadEvent(LoggerMode newLogWorldGenLoadEvent) {
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logWorldGenLoadEvent").value = newLogWorldGenLoadEvent;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugSwitch.logWorldGenLoadEvent");
}
@Override
public LoggerMode getLogLodBuilderEvent() {
return (LoggerMode) ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logLodBuilderEvent").value;
}
@Override
public void setLogLodBuilderEvent(LoggerMode newLogLodBuilderEvent) {
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logLodBuilderEvent").value = newLogLodBuilderEvent;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugSwitch.logLodBuilderEvent");
}
@Override
public LoggerMode getLogRendererBufferEvent() {
return (LoggerMode) ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logRendererBufferEvent").value;
}
@Override
public void setLogRendererBufferEvent(LoggerMode newLogRendererBufferEvent) {
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logRendererBufferEvent").value = newLogRendererBufferEvent;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugSwitch.logRendererBufferEvent");
}
@Override
public LoggerMode getLogRendererGLEvent() {
return (LoggerMode) ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logRendererGLEvent").value;
}
@Override
public void setLogRendererGLEvent(LoggerMode newLogRendererGLEvent) {
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logRendererGLEvent").value = newLogRendererGLEvent;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugSwitch.logRendererGLEvent");
}
@Override
public LoggerMode getLogFileReadWriteEvent() {
return (LoggerMode) ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logFileReadWriteEvent").value;
}
@Override
public void setLogFileReadWriteEvent(LoggerMode newLogFileReadWriteEvent) {
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logFileReadWriteEvent").value = newLogFileReadWriteEvent;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugSwitch.logFileReadWriteEvent");
}
@Override
public LoggerMode getLogFileSubDimEvent() {
return (LoggerMode) ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logFileSubDimEvent").value;
}
@Override
public void setLogFileSubDimEvent(LoggerMode newLogFileSubDimEvent) {
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logFileSubDimEvent").value = newLogFileSubDimEvent;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugSwitch.logFileSubDimEvent");
}
@Override
public LoggerMode getLogNetworkEvent() {
return (LoggerMode) ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logNetworkEvent").value;
}
@Override
public void setLogNetworkEvent(LoggerMode newLogNetworkEvent) {
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugSwitch.logNetworkEvent").value = newLogNetworkEvent;
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugSwitch.logNetworkEvent");
}
}
}
public static class Buffers implements IBuffers
{
@Override
public GpuUploadMethod getGpuUploadMethod()
{
return Config.Client.Advanced.Buffers.gpuUploadMethod;
}
@Override
public void setGpuUploadMethod(GpuUploadMethod newDisableVanillaFog)
{
ConfigGui.editSingleOption.getEntry("client.advanced.buffers.gpuUploadMethod").value = newDisableVanillaFog;
ConfigGui.editSingleOption.saveOption("client.advanced.buffers.gpuUploadMethod");
}
@Override
public int getGpuUploadPerMegabyteInMilliseconds()
{
return Config.Client.Advanced.Buffers.gpuUploadPerMegabyteInMilliseconds;
}
@Override
public void setGpuUploadPerMegabyteInMilliseconds(int newMilliseconds) {
ConfigGui.editSingleOption.getEntry("client.advanced.buffers.gpuUploadPerMegabyteInMilliseconds").value = newMilliseconds;
ConfigGui.editSingleOption.saveOption("client.advanced.buffers.gpuUploadPerMegabyteInMilliseconds");
}
@Override
public BufferRebuildTimes getRebuildTimes()
{
return Config.Client.Advanced.Buffers.rebuildTimes;
}
@Override
public void setRebuildTimes(BufferRebuildTimes newBufferRebuildTimes)
{
ConfigGui.editSingleOption.getEntry("client.advanced.buffers.newBufferRebuildTimes").value = newBufferRebuildTimes;
ConfigGui.editSingleOption.saveOption("client.advanced.buffers.newBufferRebuildTimes");
}
}
@Override
public boolean getLodOnlyMode() {
return Config.Client.Advanced.lodOnlyMode;
}
@Override
public void setLodOnlyMode(boolean newLodOnlyMode) {
ConfigGui.editSingleOption.getEntry("client.advanced.buffers.lodOnlyMode").value = newLodOnlyMode;
ConfigGui.editSingleOption.saveOption("client.advanced.buffers.lodOnlyMode");
}
}
}
}
@@ -1,23 +1,4 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.gui;
package com.seibel.lod.common.wrappers.config;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
@@ -30,12 +11,9 @@ import net.minecraft.resources.ResourceLocation;
* Creates a button with a texture on it
*/
public class TexturedButtonWidget extends ImageButton {
#if POST_MC_1_17_1
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, ResourceLocation texture, OnPress pressAction) {
super(x, y, width, height, u, v, texture, pressAction);
}
#endif
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation texture, int textureWidth, int textureHeight, OnPress pressAction) {
super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction);
}
@@ -50,15 +28,9 @@ public class TexturedButtonWidget extends ImageButton {
@Override
public void renderButton(PoseStack matrices, int mouseX, int mouseY, float delta) {
#if PRE_MC_1_17_1
Minecraft.getInstance().getTextureManager().bind(WIDGETS_LOCATION);
RenderSystem.color4f(1.0F, 1.0F, 1.0F, this.alpha);
#else
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderTexture(0, WIDGETS_LOCATION);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha);
#endif
int i = this.getYImage(this.isHovered);
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
@@ -1,458 +0,0 @@
package com.seibel.lod.common.wrappers.gui;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
// Logger (for debug stuff)
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.config.file.ConfigFileHandling;
import com.seibel.lod.core.config.types.AbstractConfigType;
import com.seibel.lod.core.config.types.ConfigCategory;
import com.seibel.lod.core.config.types.ConfigEntry;
// Uses https://github.com/TheElectronWill/night-config for toml (only for Fabric since Forge already includes this)
// Gets info from our own mod
import com.seibel.lod.core.config.*;
// Minecraft imports
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiComponent;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.client.resources.language.I18n; // translation
#if POST_MC_1_17_1
import net.minecraft.client.gui.narration.NarratableEntry;
#endif
#if PRE_MC_1_19
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
#endif
/**
* Based upon TinyConfig but is highly modified
* https://github.com/Minenash/TinyConfig
*
* Credits to Motschen
*
* @author coolGi
* @version 4-28-2022
*/
// FLOATS DONT WORK WITH THIS
@SuppressWarnings("unchecked")
public abstract class ClassicConfigGUI {
/*
This would be removed later on
*/
//==============//
// Initializers //
//==============//
// Some regexes to check if an input is valid
private static final Pattern INTEGER_ONLY_REGEX = Pattern.compile("(-?[0-9]*)");
private static final Pattern DECIMAL_ONLY_REGEX = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
private static class ConfigScreenConfigs {
// This contains all the configs for the configs
public static final int SpaceFromRightScreen = 10;
public static final int ButtonWidthSpacing = 5;
public static final int ResetButtonWidth = 40;
}
/**
* The terribly coded old stuff
*/
public static class EntryInfo {
Object widget;
Map.Entry<EditBox, Component> error;
String tempValue;
int index;
}
/**
* creates a text field
*/
private static void textField(AbstractConfigType info, Function<String, Number> func, Pattern pattern, boolean cast) {
boolean isNumber = pattern != null;
((EntryInfo) info.guiValue).widget = (BiFunction<EditBox, Button, Predicate<String>>) (editBox, button) -> stringValue ->
{
stringValue = stringValue.trim();
if (!(stringValue.isEmpty() || !isNumber || pattern.matcher(stringValue).matches()))
return false;
Number value = 0;
((EntryInfo) info.guiValue).error = null;
if (isNumber && !stringValue.isEmpty() && !stringValue.equals("-") && !stringValue.equals(".")) {
value = func.apply(stringValue);
#if PRE_MC_1_19
((EntryInfo) info.guiValue).error = ((ConfigEntry) info).isValid(value) == 0 ? null : new AbstractMap.SimpleEntry<>(editBox, new TextComponent(((ConfigEntry) info).isValid(value) == -1 ?
#else
((EntryInfo) info.guiValue).error = ((ConfigEntry) info).isValid(value) == 0 ? null : new AbstractMap.SimpleEntry<>(editBox, Component.translatable(((ConfigEntry) info).isValid(value) == -1 ?
#endif
"§cMinimum " + "length" + (cast ? " is " + (int) ((ConfigEntry) info).getMin() : " is " + ((ConfigEntry) info).getMin()) :
"§cMaximum " + "length" + (cast ? " is " + (int) ((ConfigEntry) info).getMax() : " is " + ((ConfigEntry) info).getMax())));
}
((EntryInfo) info.guiValue).tempValue = stringValue;
editBox.setTextColor(((ConfigEntry) info).isValid(value) == 0 ? 0xFFFFFFFF : 0xFFFF7777);
// button.active = entries.stream().allMatch(e -> e.inLimits);
if (((ConfigEntry) info).isValid(value) == 0 && info.getType() != List.class) {
if (!cast)
((ConfigEntry) info).setWithoutSaving(value);
else
((ConfigEntry) info).setWithoutSaving(value.intValue());
}
// else if (((ConfigEntry) info).isValid() == 0)
// {
// if (((List<String>) info.get()).size() == ((EntryInfo) info.guiValue).index)
// info.set(((List<String>) info.get()).add(""));
// info.set(((List<String>) info.get()).set(((EntryInfo) info.guiValue).index, Arrays.stream(((EntryInfo) info.guiValue).tempValue.replace("[", "").replace("]", "").split(", ")).collect(Collectors.toList()).get(0)));
// }
return true;
};
}
//==============//
// GUI handling //
//==============//
/**
* if you want to get this config gui's screen call this
*/
public static Screen getScreen(ConfigBase configBase, Screen parent, String category) {
return new ConfigScreen(configBase, parent, category);
}
/**
* Pain
*/
private static class ConfigScreen extends Screen {
protected ConfigScreen(ConfigBase configBase, Screen parent, String category) {
#if PRE_MC_1_19
super(new TranslatableComponent(
#else
super(Component.translatable(
#endif
I18n.exists(configBase.modID + ".config" + (category.isEmpty() ? "." + category : "") + ".title") ?
configBase.modID + ".config.title" :
configBase.modID + ".config" + (category.isEmpty() ? "" : "." + category) + ".title")
);
this.configBase = configBase;
this.parent = parent;
this.category = category;
this.translationPrefix = configBase.modID + ".config.";
}
private final ConfigBase configBase;
private final String translationPrefix;
private final Screen parent;
private final String category;
private ConfigListWidget list;
private boolean reload = false;
// Real Time config update //
@Override
public void tick() {
super.tick();
}
/**
* When you close it, it goes to the previous screen and saves
*/
@Override
public void onClose() {
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
Objects.requireNonNull(minecraft).setScreen(this.parent);
}
// addRenderableWidget in 1.17 and over
// addButton in 1.16 and below
private Button addBtn(Button button) {
#if PRE_MC_1_17_1
this.addButton(button);
#else
this.addRenderableWidget(button);
#endif
return button;
}
@Override
protected void init() {
super.init();
if (!reload)
ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile();
addBtn(new Button(this.width / 2 - 154, this.height - 28, 150, 20, CommonComponents.GUI_CANCEL, button -> {
ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile();
Objects.requireNonNull(minecraft).setScreen(parent);
}));
Button done = addBtn(new Button(this.width / 2 + 4, this.height - 28, 150, 20, CommonComponents.GUI_DONE, (button) -> {
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
Objects.requireNonNull(minecraft).setScreen(parent);
}));
this.list = new ConfigListWidget(this.minecraft, this.width * 2, this.height, 32, this.height - 32, 25);
if (this.minecraft != null && this.minecraft.level != null)
this.list.setRenderBackground(false);
this.addWidget(this.list);
for (AbstractConfigType info : ConfigBase.INSTANCE.entries) {
if (info.getCategory().matches(category) && info.getAppearance().showInGui) {
initEntry(info, this.translationPrefix);
#if PRE_MC_1_19
TranslatableComponent name = new TranslatableComponent(translationPrefix + info.getNameWCategory());
#else
Component name = Component.translatable(translationPrefix + info.getNameWCategory());
#endif
if (ConfigEntry.class.isAssignableFrom(info.getClass())) {
#if PRE_MC_1_19
Button resetButton = new Button(this.width - ConfigScreenConfigs.SpaceFromRightScreen - 150 - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth, 0, ConfigScreenConfigs.ResetButtonWidth, 20, new TextComponent("Reset").withStyle(ChatFormatting.RED), (button -> {
#else
Button resetButton = new Button(this.width - ConfigScreenConfigs.SpaceFromRightScreen - 150 - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth, 0, ConfigScreenConfigs.ResetButtonWidth, 20, Component.translatable("Reset").withStyle(ChatFormatting.RED), (button -> {
#endif
((ConfigEntry) info).setWithoutSaving(((ConfigEntry) info).getDefaultValue());
((EntryInfo) info.guiValue).index = 0;
this.reload = true;
Objects.requireNonNull(minecraft).setScreen(this);
}));
if (((EntryInfo) info.guiValue).widget instanceof Map.Entry) {
Map.Entry<Button.OnPress, Function<Object, Component>> widget = (Map.Entry<Button.OnPress, Function<Object, Component>>) ((EntryInfo) info.guiValue).widget;
if (info.getType().isEnum())
#if PRE_MC_1_19
widget.setValue(value -> new TranslatableComponent(translationPrefix + "enum." + info.getType().getSimpleName() + "." + info.get().toString()));
#else
widget.setValue(value -> Component.translatable(translationPrefix + "enum." + info.getType().getSimpleName() + "." + info.get().toString()));
#endif
this.list.addButton(new Button(this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen, 0, 150, 20, widget.getValue().apply(info.get()), widget.getKey()), resetButton, null, name);
} else if (((EntryInfo) info.guiValue).widget != null) {
EditBox widget = new EditBox(font, this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen + 2, 0, 150 - 4, 20, null);
widget.setMaxLength(150);
widget.insertText(String.valueOf(info.get()));
Predicate<String> processor = ((BiFunction<EditBox, Button, Predicate<String>>) ((EntryInfo) info.guiValue).widget).apply(widget, done);
widget.setFilter(processor);
this.list.addButton(widget, resetButton, null, name);
}
} else if (ConfigCategory.class.isAssignableFrom(info.getClass())) {
Button widget = new Button(this.width / 2 - 100, this.height - 28, 100 * 2, 20, name, (button -> {
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
Objects.requireNonNull(minecraft).setScreen(ClassicConfigGUI.getScreen(this.configBase, this, ((ConfigCategory) info).getDestination()));
}));
this.list.addButton(widget, null, null, null);
}
}
}
}
@Override
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices); // Renders background
this.list.render(matrices, mouseX, mouseY, delta); // Render buttons
drawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
// Render the tooltip only if it can find a tooltip in the language file
for (AbstractConfigType info : ConfigBase.INSTANCE.entries) {
if (info.getCategory().matches(category) && info.getAppearance().showInGui) {
if (list.getHoveredButton(mouseX, mouseY).isPresent()) {
AbstractWidget buttonWidget = list.getHoveredButton(mouseX, mouseY).get();
Component text = ButtonEntry.buttonsWithText.get(buttonWidget);
#if PRE_MC_1_19
TranslatableComponent name = new TranslatableComponent(this.translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.getName());
#else
Component name = Component.translatable(this.translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.getName());
#endif
String key = translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.getName() + ".@tooltip";
if (((EntryInfo) info.guiValue).error != null && text.equals(name))
renderTooltip(matrices, (Component) ((EntryInfo) info.guiValue).error.getValue(), mouseX, mouseY);
else if (I18n.exists(key) && (text != null && text.equals(name))) {
List<Component> list = new ArrayList<>();
for (String str : I18n.get(key).split("\n"))
#if PRE_MC_1_19
list.add(new TextComponent(str));
#else
list.add(Component.translatable(str));
#endif
renderComponentTooltip(matrices, list, mouseX, mouseY);
}
}
}
}
super.render(matrices, mouseX, mouseY, delta);
}
}
private static void initEntry(AbstractConfigType info, String translationPrefix) {
info.guiValue = new EntryInfo();
Class<?> fieldClass = info.getType();
if (ConfigEntry.class.isAssignableFrom(info.getClass())) {
if (fieldClass == Integer.class) {
// For int
textField(info, Integer::parseInt, INTEGER_ONLY_REGEX, true);
} else if (fieldClass == Double.class) {
// For double
textField(info, Double::parseDouble, DECIMAL_ONLY_REGEX, false);
} else if (fieldClass == String.class || fieldClass == List.class) {
// For string or list
textField(info, String::length, null, true);
} else if (fieldClass == Boolean.class) {
// For boolean
#if PRE_MC_1_19
Function<Object, Component> func = value -> new TextComponent((Boolean) value ? "True" : "False").withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
#else
Function<Object, Component> func = value -> Component.translatable((Boolean) value ? "True" : "False").withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
#endif
((EntryInfo) info.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
((ConfigEntry) info).setWithoutSaving(!(Boolean) info.get());
button.setMessage(func.apply(info.get()));
}, func);
}
else if (fieldClass.isEnum())
{
// For enum
List<?> values = Arrays.asList(info.getType().getEnumConstants());
#if PRE_MC_1_19
Function<Object, Component> func = value -> new TranslatableComponent(translationPrefix + "enum." + fieldClass.getSimpleName() + "." + info.get().toString());
#else
Function<Object, Component> func = value -> Component.translatable(translationPrefix + "enum." + fieldClass.getSimpleName() + "." + info.get().toString());
#endif
((EntryInfo) info.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
int index = values.indexOf(info.get()) + 1;
info.set(values.get(index >= values.size() ? 0 : index));
button.setMessage(func.apply(info.get()));
}, func);
}
} else if (ConfigCategory.class.isAssignableFrom(info.getClass())) {
// if (!info.info.getName().equals(""))
// info.name = new TranslatableComponent(info.info.getName());
}
// return info;
}
public static class ConfigListWidget extends ContainerObjectSelectionList<ButtonEntry> {
Font textRenderer;
public ConfigListWidget(Minecraft minecraftClient, int i, int j, int k, int l, int m) {
super(minecraftClient, i, j, k, l, m);
this.centerListVertically = false;
textRenderer = minecraftClient.font;
}
public void addButton(AbstractWidget button, AbstractWidget resetButton, AbstractWidget indexButton, Component text) {
this.addEntry(ButtonEntry.create(button, text, resetButton, indexButton));
}
@Override
public int getRowWidth() {
return 10000;
}
public Optional<AbstractWidget> getHoveredButton(double mouseX, double mouseY) {
for (ButtonEntry buttonEntry : this.children()) {
if (buttonEntry.button != null && buttonEntry.button.isMouseOver(mouseX, mouseY)) {
return Optional.of(buttonEntry.button);
}
}
return Optional.empty();
}
}
public static class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry> {
private static final Font textRenderer = Minecraft.getInstance().font;
public final AbstractWidget button;
private final AbstractWidget resetButton;
private final AbstractWidget indexButton;
private final Component text;
private final List<AbstractWidget> children = new ArrayList<>();
public static final Map<AbstractWidget, Component> buttonsWithText = new HashMap<>();
private ButtonEntry(AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton) {
buttonsWithText.put(button, text);
this.button = button;
this.resetButton = resetButton;
this.text = text;
this.indexButton = indexButton;
if (button != null)
children.add(button);
if (resetButton != null)
children.add(resetButton);
if (indexButton != null)
children.add(indexButton);
}
public static ButtonEntry create(AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton) {
return new ButtonEntry(button, text, resetButton, indexButton);
}
@Override
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
if (button != null) {
button.y = y;
button.render(matrices, mouseX, mouseY, tickDelta);
}
if (resetButton != null) {
resetButton.y = y;
resetButton.render(matrices, mouseX, mouseY, tickDelta);
}
if (indexButton != null) {
indexButton.y = y;
indexButton.render(matrices, mouseX, mouseY, tickDelta);
}
if (text != null && (!text.getString().contains("spacer") || button != null))
GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF);
}
@Override
public List<? extends GuiEventListener> children() {
return children;
}
// Only for 1.17 and over
// Remove in 1.16 and below
#if POST_MC_1_17_1
@Override
public List<? extends NarratableEntry> narratables() {
return children;
}
#endif
}
}
@@ -1,94 +0,0 @@
package com.seibel.lod.common.wrappers.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.config.gui.AbstractScreen;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.screens.Screen;
import java.util.*;
public class ConfigScreenMC {
public static Screen getScreen(Screen parent, AbstractScreen screen) {
return new ConfigScreenRenderer(parent, screen);
}
private static class ConfigScreenRenderer extends Screen {
private final Screen parent;
private ConfigListWidget list;
private AbstractScreen screen;
#if PRE_MC_1_19
public static net.minecraft.network.chat.TranslatableComponent translate (String str, Object... args) {
return new net.minecraft.network.chat.TranslatableComponent(str, args);
}
#else
public static net.minecraft.network.chat.MutableComponent translate (String str, Object... args) {
return net.minecraft.network.chat.Component.translatable(str, args);
}
#endif
protected ConfigScreenRenderer(Screen parent, AbstractScreen screen) {
super(translate(ModInfo.ID + ".config.title"));
this.parent = parent;
this.screen = screen;
}
@Override
protected void init() {
// super.init();
screen.width = this.width;
screen.height = this.height;
screen.init(); // Init our own config screen
this.list = new ConfigListWidget(this.minecraft, this.width, this.height, 0, this.height, 25); // Select the area to tint
if (this.minecraft != null && this.minecraft.level != null) // Check if in game
this.list.setRenderBackground(false); // Disable from rendering
this.addWidget(this.list); // Add the tint to the things to be rendered
}
@Override
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices); // Render background
this.list.render(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
screen.width = this.width; // Is there a way to only call this when the window changes the size
screen.height = this.height; // Is there a way to only call this when the window changes the size
screen.mouseX = mouseX;
screen.mouseY = mouseY;
screen.render(delta); // Render everything on the main screen
super.render(matrices, mouseX, mouseY, delta); // Render the vanilla stuff (currently only used for the background and tint)
}
@Override
public void tick() {
screen.tick();
if (screen.close)
onClose();
}
@Override
public void onClose() {
screen.onClose();
Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen
}
// For checking if it should close when you press the escape key
@Override
public boolean shouldCloseOnEsc() {
return screen.shouldCloseOnEsc;
}
}
public static class ConfigListWidget extends ContainerObjectSelectionList {
public ConfigListWidget(Minecraft minecraftClient, int i, int j, int k, int l, int m) {
super(minecraftClient, i, j, k, l, m);
this.centerListVertically = false;
}
}
}
@@ -1,22 +0,0 @@
package com.seibel.lod.common.wrappers.gui;
import com.seibel.lod.core.config.ConfigBase;
import com.seibel.lod.core.config.gui.ConfigScreen;
import net.minecraft.client.gui.screens.Screen;
public class GetConfigScreen {
public static type useScreen = type.Classic;
public static enum type {
Classic,
OpenGL;
}
public static Screen getScreen(Screen parent) {
if (useScreen == type.Classic) {
return ClassicConfigGUI.getScreen(ConfigBase.INSTANCE, parent, "client");
} else if (useScreen == type.OpenGL) {
return ConfigScreenMC.getScreen(parent, new ConfigScreen());
}
return null;
}
}
@@ -1,17 +0,0 @@
package com.seibel.lod.common.wrappers.gui;
import com.seibel.lod.core.wrapperInterfaces.config.ILangWrapper;
import net.minecraft.client.resources.language.I18n;
public class LangWrapper implements ILangWrapper {
public static final LangWrapper INSTANCE = new LangWrapper();
@Override
public boolean langExists(String str) {
return I18n.exists(str);
}
@Override
public String getLang(String str) {
return I18n.get(str);
}
}
@@ -1,188 +0,0 @@
package com.seibel.lod.common.wrappers.gui.updater;
import com.google.common.collect.Lists;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.vertex.PoseStack;
import com.seibel.lod.common.wrappers.gui.ClassicConfigGUI;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.jar.JarUtils;
import com.seibel.lod.core.jar.installer.MarkdownFormatter;
import com.seibel.lod.core.jar.installer.ModrinthGetter;
import com.seibel.lod.core.jar.updater.SelfUpdater;
import net.minecraft.client.Minecraft;
import net.minecraft.client.StringSplitter;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiComponent;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.ImageButton;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.FormattedText;
import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.FormattedCharSequence;
import java.util.*;
/**
* The screen that pops up if the mod has an update.
*
* @author coolGi
*/
// TODO: After finishing the config, rewrite this in openGL as well
// TODO: Make this
public class ChangelogScreen extends Screen {
private Screen parent;
private String versionID;
private List<String> changelog;
private TextArea changelogArea;
public ChangelogScreen(Screen parent, String versionID) {
super(translate(ModInfo.ID + ".updater.title"));
this.parent = parent;
this.versionID = versionID;
this.changelog = new ArrayList<>();
// Get the release changelog and split it by the new lines
List<String> unwrappedChangelog =
List.of(new MarkdownFormatter.MinecraftFormat().convertTo( // This formats markdown to minecraft's "§" characters
ModrinthGetter.changeLogs.get(versionID)
).split("\\n"));
// Makes the words wrap around to not go off the screen
for (String str: unwrappedChangelog) {
this.changelog.addAll(
MarkdownFormatter.splitString(str, 75)
);
}
// Debugging
// System.out.println(this.changelog);
}
@Override
protected void init() {
super.init();
this.addBtn( // Close
new Button(5, this.height - 25, 100, 20, translate(ModInfo.ID + ".general.back"), (btn) -> {
this.onClose();
})
);
this.changelogArea = new TextArea(this.minecraft, this.width*2, this.height, 32, this.height - 32, 10);
for (int i = 0; i < changelog.size(); i++) {
this.changelogArea.addButton(new TextComponent(changelog.get(i)));
// drawString(matrices, this.font, changelog.get(i), this.width / 2 - 175, this.height / 2 - 100 + i*10, 0xFFFFFF);
}
}
@Override
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices); // Render background
// Set the scroll position to the mouse height relative to the screen
this.changelogArea.setScrollAmount(
((double) mouseY)/((double) this.height) * this.changelogArea.getMaxScroll()
);
this.changelogArea.render(matrices, mouseX, mouseY, delta); // Render the changelog
super.render(matrices, mouseX, mouseY, delta); // Render the buttons
drawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
}
@Override
public void onClose() {
Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen
}
// addRenderableWidget in 1.17 and over
// addButton in 1.16 and below
private void addBtn(Button button) {
#if PRE_MC_1_17_1
this.addButton(button);
#else
this.addRenderableWidget(button);
#endif
}
#if PRE_MC_1_19
public static net.minecraft.network.chat.TranslatableComponent translate (String str, Object... args) {
return new net.minecraft.network.chat.TranslatableComponent(str, args);
}
#else
public static net.minecraft.network.chat.MutableComponent translate (String str, Object... args) {
return net.minecraft.network.chat.Component.translatable(str, args);
}
#endif
public static class TextArea extends ContainerObjectSelectionList<ButtonEntry> {
Font textRenderer;
public TextArea(Minecraft minecraftClient, int i, int j, int k, int l, int m) {
super(minecraftClient, i, j, k, l, m);
this.centerListVertically = false;
textRenderer = minecraftClient.font;
}
public void addButton(Component text) {
this.addEntry(ButtonEntry.create(text));
}
@Override
public int getRowWidth() {
return 10000;
}
}
public static class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry> {
private static final Font textRenderer = Minecraft.getInstance().font;
private final Component text;
private final List<AbstractWidget> children = new ArrayList<>();
private ButtonEntry(Component text) {
this.text = text;
}
public static ButtonEntry create(Component text) {
return new ButtonEntry(text);
}
@Override
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF);
}
@Override
public List<? extends GuiEventListener> children() {
return children;
}
#if POST_MC_1_17_1
@Override
public List<? extends NarratableEntry> narratables() {
return children;
}
#endif
}
}
@@ -1,159 +0,0 @@
package com.seibel.lod.common.wrappers.gui.updater;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.vertex.PoseStack;
import com.seibel.lod.common.wrappers.gui.TexturedButtonWidget;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.jar.JarUtils;
import com.seibel.lod.core.jar.installer.ModrinthGetter;
import com.seibel.lod.core.jar.updater.SelfUpdater;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.ImageButton;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.resources.ResourceLocation;
import java.util.*;
/**
* The screen that pops up if the mod has an update.
*
* @author coolGi
*/
// TODO: After finishing the config, rewrite this in openGL as well
// and also maybe add this suggestion https://discord.com/channels/881614130614767666/1035863487110467625/1035949054485594192
public class UpdateModScreen extends Screen {
private Screen parent;
private String newVersionID;
public UpdateModScreen(Screen parent, String newVersionID) {
super(translate(ModInfo.ID + ".updater.title"));
this.parent = parent;
this.newVersionID = newVersionID;
}
@Override
protected void init() {
super.init();
try {
// We cannot get assets from the root of the mod so we use this hack
// TODO: Load the icon.png and logo.png in the mod initialise rather than here
ResourceLocation logoLocation = new ResourceLocation(ModInfo.ID, "logo.png");
Minecraft.getInstance().getTextureManager().register(
logoLocation,
new DynamicTexture(NativeImage.read(JarUtils.accessFile("logo.png")))
);
// Logo image
this.addBtn(new ImageButton(
// Where the button is on the screen
this.width / 2 - 65, this.height / 2 - 110,
// Width and height of the button
130, 65,
// Offset
0, 0,
// Some textuary stuff
0, logoLocation, 130, 65,
// Create the button and tell it where to go
// For now it goes to the client option by default
(buttonWidget) -> System.out.println("Nice, you found an easter egg :)"), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
// Add a title to the button
translate(ModInfo.ID + ".updater.title")
));
} catch (Exception e) { e.printStackTrace(); }
this.addBtn(new TexturedButtonWidget(
// Where the button is on the screen
this.width / 2 - 97, this.height / 2 + 8,
// Width and height of the button
20, 20,
// Offset
0, 0,
// Some textuary stuff
0, new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"), 20, 20,
// Create the button and tell it where to go
// For now it goes to the client option by default
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(new ChangelogScreen(this, this.newVersionID)), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
// Add a title to the button
translate(ModInfo.ID + ".updater.title")
));
this.addBtn( // Update
new Button(this.width / 2 - 75, this.height / 2 + 8, 150, 20, translate(ModInfo.ID + ".updater.update"), (btn) -> {
SelfUpdater.deleteOldOnClose = true;
SelfUpdater.updateMod();
this.onClose();
})
);
this.addBtn( // Silent update
new Button(this.width / 2 - 75, this.height / 2 + 30, 150, 20, translate(ModInfo.ID + ".updater.silent"), (btn) -> {
Config.Client.AutoUpdater.promptForUpdate.set(false);
SelfUpdater.updateMod();
this.onClose();
})
);
this.addBtn( // Later (not now)
new Button(this.width / 2 + 2, this.height / 2 + 70, 100, 20, translate(ModInfo.ID + ".updater.later"), (btn) -> {
this.onClose();
})
);
this.addBtn( // Never
new Button(this.width / 2 - 102, this.height / 2 + 70, 100, 20, translate(ModInfo.ID + ".updater.never"), (btn) -> {
Config.Client.AutoUpdater.enableAutoUpdater.set(false);
this.onClose();
})
);
}
@Override
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices); // Render background
// Render the text's
drawCenteredString(matrices, this.font, translate(ModInfo.ID + ".updater.text1"), this.width / 2, this.height / 2 - 35, 0xFFFFFF);
drawCenteredString(matrices, this.font, translate(ModInfo.ID + ".updater.text2", ModInfo.VERSION, ModrinthGetter.releaseNames.get(this.newVersionID)), this.width / 2, this.height / 2 -20, 0x52FD52);
// TODO: add the tooltips for the buttons
super.render(matrices, mouseX, mouseY, delta); // Render the buttons
// TODO: Add tooltips
}
@Override
public void onClose() {
Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen
}
// addRenderableWidget in 1.17 and over
// addButton in 1.16 and below
private void addBtn(Button button) {
#if PRE_MC_1_17_1
this.addButton(button);
#else
this.addRenderableWidget(button);
#endif
}
#if PRE_MC_1_19
public static net.minecraft.network.chat.TranslatableComponent translate (String str, Object... args) {
return new net.minecraft.network.chat.TranslatableComponent(str, args);
}
#else
public static net.minecraft.network.chat.MutableComponent translate (String str, Object... args) {
return net.minecraft.network.chat.Component.translatable(str, args);
}
#endif
}
@@ -1,54 +1,65 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
* 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
* it under the terms of the GNU 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.
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.common.wrappers.minecraft;
import java.awt.Color;
import java.io.File;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import com.mojang.blaze3d.platform.NativeImage;
import com.seibel.lod.common.wrappers.world.ClientLevelWrapper;
import com.seibel.lod.common.wrappers.world.ServerLevelWrapper;
import com.mojang.blaze3d.platform.Window;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.enums.ELodDirection;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.lod.core.wrapperInterfaces.misc.ILightMapWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.common.wrappers.McObjectConverter;
import com.seibel.lod.core.pos.DhBlockPos;
import com.seibel.lod.core.pos.DhChunkPos;
import com.seibel.lod.common.wrappers.block.BlockPosWrapper;
import com.seibel.lod.common.wrappers.chunk.ChunkPosWrapper;
import com.seibel.lod.common.wrappers.misc.LightMapWrapper;
import com.seibel.lod.common.wrappers.world.DimensionTypeWrapper;
import com.seibel.lod.common.wrappers.world.WorldWrapper;
import net.minecraft.CrashReport;
import net.minecraft.client.Minecraft;
import net.minecraft.client.Options;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.server.IntegratedServer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
#if PRE_MC_1_19
import net.minecraft.network.chat.TextComponent;
#endif
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import org.apache.logging.log4j.Logger;
import net.minecraft.world.level.dimension.DimensionType;
import org.jetbrains.annotations.Nullable;
/**
@@ -57,11 +68,8 @@ import org.jetbrains.annotations.Nullable;
* @author James Seibel
* @version 3-5-2022
*/
//@Environment(EnvType.CLIENT)
public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecraftSharedWrapper
public class MinecraftClientWrapper implements IMinecraftClientWrapper
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
public static final MinecraftClientWrapper INSTANCE = new MinecraftClientWrapper();
public final Minecraft mc = Minecraft.getInstance();
@@ -107,7 +115,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
//=================//
@Override
public float getShade(ELodDirection lodDirection) {
public float getShade(LodDirection lodDirection) {
if (mc.level != null)
{
Direction mcDir = McObjectConverter.Convert(lodDirection);
@@ -140,6 +148,55 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
return mc.getCurrentServer().version.getString();
}
/** Returns the dimension the player is currently in */
@Override
public IDimensionTypeWrapper getCurrentDimension()
{
if (mc.player != null)
return DimensionTypeWrapper.getDimensionTypeWrapper(mc.player.level.dimensionType());
else return null;
}
@Override
public String getCurrentDimensionId()
{
return LodUtil.getDimensionIDFromWorld(WorldWrapper.getWorldWrapper(mc.level));
}
/** This texture changes every frame */
@Override
public ILightMapWrapper getCurrentLightMap()
{
// get the current lightMap if the cache is empty
if (lightMap == null)
{
LightTexture tex = mc.gameRenderer.lightTexture();
lightMap = tex.lightPixels;
}
return new LightMapWrapper(lightMap);
}
/**
* Returns the color int at the given pixel coordinates
* from the current lightmap.
* @param blockLight x location in texture space
* @param skyLight z location in texture space
*/
@Override
public int getColorIntFromLightMap(int blockLight, int skyLight)
{
if (lightMap == null)
{
//sendChatMessage("new");
// make sure the lightMap is up-to-date
getCurrentLightMap();
}
return lightMap.getPixelRGBA(blockLight, skyLight);
}
//=============//
// Simple gets //
//=============//
@@ -156,21 +213,22 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
}
@Override
public DhBlockPos getPlayerBlockPos()
public BlockPosWrapper getPlayerBlockPos()
{
BlockPos playerPos = getPlayer().blockPosition();
return new DhBlockPos(playerPos.getX(), playerPos.getY(), playerPos.getZ());
return new BlockPosWrapper(playerPos.getX(), playerPos.getY(), playerPos.getZ());
}
@Override
public DhChunkPos getPlayerChunkPos()
public ChunkPosWrapper getPlayerChunkPos()
{
#if PRE_MC_1_17_1
ChunkPos playerPos = new ChunkPos(getPlayer().blockPosition());
#else
ChunkPos playerPos = getPlayer().chunkPosition();
#endif
return new DhChunkPos(playerPos.x, playerPos.z);
return new ChunkPosWrapper(playerPos.x, playerPos.z);
}
public Options getOptions()
{
return mc.options;
}
public ModelManager getModelManager()
@@ -178,11 +236,71 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
return mc.getModelManager();
}
public ClientLevel getClientLevel()
{
return mc.level;
}
@Override
public IWorldWrapper getWrappedServerWorld()
{
if (mc.level == null)
return null;
DimensionType dimension = mc.level.dimensionType();
IntegratedServer server = mc.getSingleplayerServer();
if (server == null)
return null;
ServerLevel serverWorld = null;
Iterable<ServerLevel> worlds = server.getAllLevels();
for (ServerLevel world : worlds)
{
if (world.dimensionType() == dimension)
{
serverWorld = world;
break;
}
}
return WorldWrapper.getWorldWrapper(serverWorld);
}
public WorldWrapper getWrappedClientLevel()
{
return WorldWrapper.getWorldWrapper(mc.level);
}
public WorldWrapper getWrappedServerLevel()
{
if (mc.level == null)
return null;
DimensionType dimension = mc.level.dimensionType();
IntegratedServer server = mc.getSingleplayerServer();
if (server == null)
return null;
Iterable<ServerLevel> worlds = server.getAllLevels();
ServerLevel returnWorld = null;
for (ServerLevel world : worlds)
{
if (world.dimensionType() == dimension)
{
returnWorld = world;
break;
}
}
return WorldWrapper.getWorldWrapper(returnWorld);
}
@Nullable
@Override
public ILevelWrapper getWrappedClientWorld()
public IWorldWrapper getWrappedClientWorld()
{
return ClientLevelWrapper.getWrapper(mc.level);
return WorldWrapper.getWorldWrapper(mc.level);
}
@Override
@@ -198,19 +316,66 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
profilerWrapper = new ProfilerWrapper(mc.getProfiler());
else if (mc.getProfiler() != profilerWrapper.profiler)
profilerWrapper.profiler = mc.getProfiler();
return profilerWrapper;
return profilerWrapper; }
public ClientPacketListener getConnection()
{
return mc.getConnection();
}
public GameRenderer getGameRenderer()
{
return mc.gameRenderer;
}
public Entity getCameraEntity()
{
return mc.cameraEntity;
}
public Window getWindow()
{
return mc.getWindow();
}
@Override
public float getSkyDarken(float partialTicks)
{
return mc.level.getSkyDarken(partialTicks);
}
public IntegratedServer getSinglePlayerServer()
{
return mc.getSingleplayerServer();
}
@Override
public boolean connectedToServer()
{
return mc.getCurrentServer() != null;
}
public ServerData getCurrentServer()
{
return mc.getCurrentServer();
}
public LevelRenderer getLevelRenderer()
{
return mc.levelRenderer;
}
/** Returns all worlds available to the server */
@Override
public ArrayList<ILevelWrapper> getAllServerWorlds()
public ArrayList<IWorldWrapper> getAllServerWorlds()
{
ArrayList<ILevelWrapper> worlds = new ArrayList<ILevelWrapper>();
ArrayList<IWorldWrapper> worlds = new ArrayList<IWorldWrapper>();
Iterable<ServerLevel> serverWorlds = mc.getSingleplayerServer().getAllLevels();
for (ServerLevel world : serverWorlds)
{
worlds.add(ServerLevelWrapper.getWrapper(world));
worlds.add(WorldWrapper.getWorldWrapper(world));
}
return worlds;
@@ -221,11 +386,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
@Override
public void sendChatMessage(String string)
{
#if PRE_MC_1_19
getPlayer().sendMessage(new TextComponent(string), getPlayer().getUUID());
#else
getPlayer().sendSystemMessage(net.minecraft.network.chat.Component.translatable(string));
#endif
}
/**
@@ -239,24 +400,13 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
@Override
public void crashMinecraft(String errorMessage, Throwable exception)
{
LOGGER.error(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft...");
ApiShared.LOGGER.error(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft...");
CrashReport report = new CrashReport(errorMessage, exception);
Minecraft.crash(report);
}
@Override
public Object getOptionsObject()
{
return mc.options;
}
@Override
public boolean isDedicatedServer() {
return false;
}
@Override
public File getInstallationDirectory() {
return mc.gameDirectory;
}
}
@@ -1,23 +0,0 @@
package com.seibel.lod.common.wrappers.minecraft;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
import net.minecraft.server.dedicated.DedicatedServer;
import java.io.File;
//@Environment(EnvType.SERVER)
public class MinecraftDedicatedServerWrapper implements IMinecraftSharedWrapper {
public static final MinecraftDedicatedServerWrapper INSTANCE = new MinecraftDedicatedServerWrapper();
private MinecraftDedicatedServerWrapper() {}
public DedicatedServer dedicatedServer = null;
@Override
public boolean isDedicatedServer() {
return true;
}
@Override
public File getInstallationDirectory() {
if (dedicatedServer == null)
throw new IllegalStateException("Trying to get Installation Direction before Dedicated server complete initialization!");
return dedicatedServer.getServerDirectory();
}
}
@@ -1,73 +1,46 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.minecraft;
import java.awt.Color;
import java.lang.invoke.MethodHandles;
import java.util.Collection;
import java.awt.*;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.stream.Collectors;
import com.mojang.blaze3d.pipeline.RenderTarget;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.pos.DhChunkPos;
import com.seibel.lod.common.wrappers.misc.LightMapWrapper;
import com.seibel.lod.core.dependencyInjection.ModAccessorInjector;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.handlers.dependencyInjection.ModAccessorHandler;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.wrapperInterfaces.misc.ILightMapWrapper;
import net.minecraft.client.renderer.LightTexture;
import com.mojang.math.Vector3f;
import com.seibel.lod.core.util.math.Mat4f;
import com.seibel.lod.core.util.math.Vec3d;
import com.seibel.lod.core.util.math.Vec3f;
import com.seibel.lod.core.objects.math.Mat4f;
import com.seibel.lod.core.objects.math.Vec3d;
import com.seibel.lod.core.objects.math.Vec3f;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IBCLibAccessor;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import com.seibel.lod.common.wrappers.McObjectConverter;
import com.seibel.lod.common.wrappers.WrapperFactory;
import com.seibel.lod.core.pos.DhBlockPos;
import com.seibel.lod.common.wrappers.block.BlockPosWrapper;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
#if PRE_MC_1_17_1
import net.minecraft.tags.FluidTags;
import net.minecraft.world.level.material.FluidState;
import org.lwjgl.opengl.GL15;
#else
import net.minecraft.world.level.material.FogType;
#endif
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.apache.logging.log4j.Logger;
/**
@@ -77,35 +50,28 @@ import org.apache.logging.log4j.Logger;
* @author James Seibel
* @version 12-12-2021
*/
//@Environment(EnvType.CLIENT)
public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
{
public static final MinecraftRenderWrapper INSTANCE = new MinecraftRenderWrapper();
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
private static final Minecraft MC = Minecraft.getInstance();
private static final GameRenderer GAME_RENDERER = MC.gameRenderer;
private static final IWrapperFactory FACTORY = WrapperFactory.INSTANCE;
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
public LightMapWrapper lightmap = null;
@Override
public Vec3f getLookAtVector()
{
Camera camera = MC.gameRenderer.getMainCamera();
Camera camera = GAME_RENDERER.getMainCamera();
Vector3f cameraDir = camera.getLookVector();
return new Vec3f(cameraDir.x(), cameraDir.y(), cameraDir.z());
}
@Override
public DhBlockPos getCameraBlockPosition()
public AbstractBlockPosWrapper getCameraBlockPosition()
{
Camera camera = MC.gameRenderer.getMainCamera();
Camera camera = GAME_RENDERER.getMainCamera();
BlockPos blockPos = camera.getBlockPosition();
return new DhBlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ());
return new BlockPosWrapper(blockPos.getX(), blockPos.getY(), blockPos.getZ());
}
@Override
@@ -117,7 +83,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override
public Vec3d getCameraExactPosition()
{
Camera camera = MC.gameRenderer.getMainCamera();
Camera camera = GAME_RENDERER.getMainCamera();
Vec3 projectedView = camera.getPosition();
return new Vec3d(projectedView.x, projectedView.y, projectedView.z);
@@ -126,35 +92,19 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override
public Mat4f getDefaultProjectionMatrix(float partialTicks)
{
#if PRE_MC_1_17_1
return McObjectConverter.Convert(Minecraft.getInstance().gameRenderer.getProjectionMatrix(Minecraft.getInstance().gameRenderer.getMainCamera(), partialTicks, true));
#else
return McObjectConverter.Convert(MC.gameRenderer.getProjectionMatrix(MC.gameRenderer.getFov(MC.gameRenderer.getMainCamera(), partialTicks, true)));
#endif
return McObjectConverter.Convert(GAME_RENDERER.getProjectionMatrix(GAME_RENDERER.getFov(GAME_RENDERER.getMainCamera(), partialTicks, true)));
}
@Override
public double getGamma()
{
#if PRE_MC_1_19
return MC.options.gamma;
#else
return MC.options.gamma().get();
#endif
}
@Override
public Color getFogColor(float partialTicks) {
if (SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("bclib"))
return ModAccessorInjector.INSTANCE.get(IBCLibAccessor.class).getFogColor(); // BCLib uses a different fog method so we need to use that instead if they are loaded
#if PRE_MC_1_17_1
float[] colorValues = new float[4];
GL15.glGetFloatv(GL15.GL_FOG_COLOR, colorValues);
#else
FogRenderer.setupColor(MC.gameRenderer.getMainCamera(), partialTicks, MC.level, 1, MC.gameRenderer.getDarkenWorldAmount(partialTicks));
FogRenderer.setupColor(GAME_RENDERER.getMainCamera(), partialTicks, MC.level, 1, GAME_RENDERER.getDarkenWorldAmount(partialTicks));
float[] colorValues = RenderSystem.getShaderFogColor();
#endif
return new Color(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
}
// getSpecialFogColor() is the same as getFogColor()
@@ -162,11 +112,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override
public Color getSkyColor() {
if (MC.level.dimensionType().hasSkyLight()) {
#if PRE_MC_1_17_1
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getBlockPosition(), MC.getFrameTime());
#else
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), MC.getFrameTime());
#endif
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
} else
return new Color(0, 0, 0);
@@ -175,42 +121,25 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override
public double getFov(float partialTicks)
{
return MC.gameRenderer.getFov(MC.gameRenderer.getMainCamera(), partialTicks, true);
return GAME_RENDERER.getFov(GAME_RENDERER.getMainCamera(), partialTicks, true);
}
/** Measured in chunks */
@Override
public int getRenderDistance()
{
#if PRE_MC_1_18_1
//FIXME: How to resolve this?
return MC.options.renderDistance;
#else
return MC.options.getEffectiveRenderDistance();
#endif
return MC.options.getEffectiveRenderDistance();
}
@Override
public int getScreenWidth()
{
int width = MC.getWindow().getWidth();
if (OPTIFINE_ACCESSOR != null)
{
// TODO remove comment after testing:
// this should fix the issue where different optifine render resolutions screw up the LOD rendering
width *= OPTIFINE_ACCESSOR.getRenderResolutionMultiplier();
}
return width;
return MC.getWindow().getWidth();
}
@Override
public int getScreenHeight()
{
int height = MC.getWindow().getHeight();
if (OPTIFINE_ACCESSOR != null)
{
height *= OPTIFINE_ACCESSOR.getRenderResolutionMultiplier();
}
return height;
return MC.getWindow().getHeight();
}
private RenderTarget getRenderTarget() {
@@ -241,14 +170,17 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
public boolean usingBackupGetVanillaRenderedChunks = false;
@Override
public HashSet<DhChunkPos> getVanillaRenderedChunks() {
ISodiumAccessor sodium = ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class);
if (sodium != null) {
public HashSet<AbstractChunkPosWrapper> getVanillaRenderedChunks()
{
ISodiumAccessor sodium = ModAccessorHandler.get(ISodiumAccessor.class);
if (sodium != null)
{
return sodium.getNormalRenderedChunks();
}
IOptifineAccessor optifine = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
if (optifine != null) {
HashSet<DhChunkPos> pos = optifine.getNormalRenderedChunks();
IOptifineAccessor optifine = ModAccessorHandler.get(IOptifineAccessor.class);
if (optifine != null)
{
HashSet<AbstractChunkPosWrapper> pos = optifine.getNormalRenderedChunks();
if (pos == null)
pos = getMaximumRenderedChunks();
return pos;
@@ -256,15 +188,14 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
if (!usingBackupGetVanillaRenderedChunks) {
try {
LevelRenderer levelRenderer = MC.levelRenderer;
Collection<LevelRenderer.RenderChunkInfo> chunks =
#if PRE_MC_1_18_1 levelRenderer.renderChunks;
#else levelRenderer.renderChunkStorage.get().renderChunks; #endif
LinkedHashSet<LevelRenderer.RenderChunkInfo> chunks = levelRenderer.renderChunkStorage.get().renderChunks;
return (chunks.stream().map((chunk) -> {
AABB chunkBoundingBox =
#if PRE_MC_1_18_2 chunk.chunk.bb;
#else chunk.chunk.getBoundingBox(); #endif
return new DhChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
#if MC_VERSION_1_18_2
AABB chunkBoundingBox = chunk.chunk.getBoundingBox();
#elif MC_VERSION_1_18_1
AABB chunkBoundingBox = chunk.chunk.bb;
#endif
return FACTORY.createChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
Math.floorDiv((int) chunkBoundingBox.minZ, 16));
}).collect(Collectors.toCollection(HashSet::new)));
} catch (LinkageError e) {
@@ -274,46 +205,133 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
+ " Using Backup Method.");
MinecraftClientWrapper.INSTANCE.sendChatMessage(
"\u00A7eOverdraw prevention will be worse than normal.");
} catch (Exception e2) {
}
LOGGER.error("getVanillaRenderedChunks Error: ", e);
} catch (Exception e2) {}
ApiShared.LOGGER.error("getVanillaRenderedChunks Error: ", e);
usingBackupGetVanillaRenderedChunks = true;
}
}
return getMaximumRenderedChunks();
}
@Override
@Deprecated
public int[] getLightmapPixels()
{
LightTexture tex = GAME_RENDERER.lightTexture();
//tex.tick(); // This call makes no sense, but it fixes pause menu flicker bug
NativeImage lightMapPixels = tex.lightTexture.getPixels();
LightMapWrapper lightMap = new LightMapWrapper(lightMapPixels);
int lightMapHeight = getLightmapTextureHeight();
int lightMapWidth = getLightmapTextureWidth();
int[] pixels = new int[lightMapWidth * lightMapHeight];
for (int u = 0; u < lightMapWidth; u++)
{
for (int v = 0; v < lightMapWidth; v++)
{
// this could probably be kept as a int, but
// it is easier to test and see the colors when debugging this way.
// When creating a new release this should be changed to the int version.
int col = lightMap.getLightValue(u, v);
// these should both create a totally white image
// int col =
// Integer.MAX_VALUE;
// int col =
// 0b11111111 + // red
// (0b11111111 << 8) + // green
// (0b11111111 << 16) + // blue
// (0b11111111 << 24); // blue
// int col =
// ((c.getRed() & 0xFF) << 16) | // blue
// ((c.getGreen() & 0xFF) << 8) | // green
// ((c.getBlue() & 0xFF)) | // red
// ((c.getAlpha() & 0xFF) << 24); // alpha
// 2D array stored in a 1D array.
// Thank you Tim from College ;)
pixels[u * lightMapWidth + v] = col;
}
}
return pixels;
}
@Override
public ILightMapWrapper getLightmapWrapper() {
return lightmap;
return new LightMapWrapper(GAME_RENDERER.lightTexture());
}
@Override
@Deprecated
public int getLightmapTextureHeight()
{
int height = -1;
LightTexture lightTexture = GAME_RENDERER.lightTexture();
if (lightTexture != null)
{
NativeImage tex = lightTexture.lightPixels;
if (tex != null)
{
height = tex.getHeight();
}
}
return height;
}
@Override
@Deprecated
public int getLightmapTextureWidth()
{
int width = -1;
LightTexture lightTexture = GAME_RENDERER.lightTexture();
if (lightTexture != null)
{
NativeImage tex = lightTexture.lightPixels;
if (tex != null)
{
width = tex.getWidth();
}
}
return width;
}
@Override
@Deprecated
public int getLightmapGLFormat() {
int glFormat = -1;
LightTexture lightTexture = GAME_RENDERER.lightTexture();
if (lightTexture != null) {
NativeImage tex = lightTexture.lightPixels;
if (tex != null) {
glFormat = tex.format().glFormat();
}
}
return glFormat;
}
@Override
public boolean isFogStateSpecial() {
#if PRE_MC_1_17_1
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
FluidState fluidState = camera.getFluidInCamera();
Entity entity = camera.getEntity();
boolean isUnderWater = (entity instanceof LivingEntity) && ((LivingEntity)entity).hasEffect(MobEffects.BLINDNESS);
isUnderWater |= fluidState.is(FluidTags.WATER);
isUnderWater |= fluidState.is(FluidTags.LAVA);
return isUnderWater;
#else
Entity entity = MC.gameRenderer.getMainCamera().getEntity();
Entity entity = GAME_RENDERER.getMainCamera().getEntity();
boolean isBlind = (entity instanceof LivingEntity) && ((LivingEntity)entity).hasEffect(MobEffects.BLINDNESS);
return MC.gameRenderer.getMainCamera().getFluidInCamera() != FogType.NONE || isBlind;
#endif
return GAME_RENDERER.getMainCamera().getFluidInCamera() != FogType.NONE || isBlind;
}
@Override
public boolean tryDisableVanillaFog() {
return true; // Handled via MixinFogRenderer in both forge and fabric
}
public void updateLightmap(NativeImage lightPixels) {
if (lightmap== null) {
lightmap = new LightMapWrapper();
}
lightmap.uploadLightmap(lightPixels);
}
}
@@ -1,22 +1,3 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.minecraft;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
@@ -1,67 +1,43 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.misc;
import com.mojang.blaze3d.platform.NativeImage;
import com.seibel.lod.core.wrapperInterfaces.misc.ILightMapWrapper;
import net.minecraft.client.renderer.LightTexture;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
/**
* @author James Seibel
* @version 11-21-2021
*/
public class LightMapWrapper implements ILightMapWrapper
{
private int textureId = 0;
static NativeImage lightMap = null;
public LightMapWrapper()
private LightTexture tex;
public LightMapWrapper(NativeImage newLightMap)
{
lightMap = newLightMap;
}
private void createLightmap(NativeImage image)
{
textureId = GL32.glGenTextures();
GL32.glBindTexture(GL32.GL_TEXTURE_2D, textureId);
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, image.format().glFormat(), image.getWidth(), image.getHeight(),
0, image.format().glFormat(), GL32.GL_UNSIGNED_BYTE, (ByteBuffer) null);
public LightMapWrapper(LightTexture lightTexture) {
tex = lightTexture;
}
public void uploadLightmap(NativeImage image)
public static void setLightMap(NativeImage newLightMap)
{
int currentBind = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, textureId);
if (textureId == 0) {
createLightmap(image);
}
// NativeImage::upload(int levelOfDetail, int xOffset, int yOffset, bool shouldCleanup?)
image.upload(0, 0, 0, false);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, currentBind);
lightMap = newLightMap;
}
@Override
public int getLightValue(int skyLight, int blockLight)
{
return lightMap.getPixelRGBA(skyLight, blockLight);
}
@Override
public void bind() {
GL32.glBindTexture(GL32.GL_TEXTURE_2D, textureId);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, tex.lightTexture.getId());
}
@Override
@@ -0,0 +1,164 @@
/*
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.common.wrappers.world;
import java.awt.Color;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.material.MaterialColor;
//This class wraps the minecraft BlockPos.Mutable (and BlockPos) class
public class BiomeWrapper implements IBiomeWrapper
{
public static final ConcurrentMap<Biome, BiomeWrapper> biomeWrapperMap = new ConcurrentHashMap<>();
private final Biome biome;
public BiomeWrapper(Biome biome)
{
this.biome = biome;
}
static public IBiomeWrapper getBiomeWrapper(Biome biome)
{
//first we check if the biome has already been wrapped
if(biomeWrapperMap.containsKey(biome) && biomeWrapperMap.get(biome) != null)
return biomeWrapperMap.get(biome);
//if it hasn't been created yet, we create it and save it in the map
BiomeWrapper biomeWrapper = new BiomeWrapper(biome);
biomeWrapperMap.put(biome, biomeWrapper);
//we return the newly created wrapper
return biomeWrapper;
}
/** Returns a color int for the given biome. */
@Override
public int getColorForBiome(int x, int z)
{
int colorInt;
switch (biome.biomeCategory)
{
case NETHER:
colorInt = Blocks.NETHERRACK.defaultBlockState().getMaterial().getColor().col;
break;
case THEEND:
colorInt = Blocks.END_STONE.defaultBlockState().getMaterial().getColor().col;
break;
case BEACH:
case DESERT:
colorInt = Blocks.SAND.defaultBlockState().getMaterial().getColor().col;
break;
case EXTREME_HILLS:
colorInt = Blocks.STONE.defaultMaterialColor().col;
break;
case MUSHROOM:
colorInt = MaterialColor.COLOR_LIGHT_GRAY.col;
break;
case ICY:
colorInt = Blocks.SNOW.defaultMaterialColor().col;
break;
case MESA:
colorInt = Blocks.RED_SAND.defaultMaterialColor().col;
break;
case OCEAN:
case RIVER:
colorInt = biome.getWaterColor();
break;
case NONE:
case FOREST:
case TAIGA:
case JUNGLE:
case PLAINS:
case SAVANNA:
case SWAMP:
default:
colorInt = biome.getGrassColor(x,z);
//FIXME: Repair what James did - LeeTom
// Color tmp = LodUtil.intToColor(biome.getGrassColor(x, z));
// tmp = tmp.darker();
// colorInt = LodUtil.colorToInt(tmp);
break;
}
return colorInt;
}
@Override public String getName()
{
return biome.toString();
}
@Override
public int getGrassTint(int x, int z)
{
return biome.getGrassColor(x, z);
}
@Override
public int getFolliageTint()
{
return biome.getFoliageColor();
}
@Override
public int getWaterTint()
{
return biome.getWaterColor();
}
@Override public boolean equals(Object obj)
{
if (this == obj)
return true;
if (!(obj instanceof BiomeWrapper))
return false;
BiomeWrapper that = (BiomeWrapper) obj;
return Objects.equals(biome, that.biome);
}
@Override public int hashCode()
{
return Objects.hash(biome);
}
}
@@ -1,163 +0,0 @@
package com.seibel.lod.common.wrappers.world;
import com.seibel.lod.api.enums.worldGeneration.EDhApiLevelType;
import com.seibel.lod.api.interfaces.world.IDhApiDimensionTypeWrapper;
import com.seibel.lod.common.wrappers.McObjectConverter;
import com.seibel.lod.common.wrappers.block.BiomeWrapper;
import com.seibel.lod.common.wrappers.block.BlockStateWrapper;
import com.seibel.lod.common.wrappers.block.cache.ClientBlockDetailMap;
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.pos.DhBlockPos;
import com.seibel.lod.core.pos.DhChunkPos;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IServerLevelWrapper;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.ChunkStatus;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.ConcurrentHashMap;
/**
*
* @version 2022-9-16
*/
public class ClientLevelWrapper implements IClientLevelWrapper
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger(ClientLevelWrapper.class.getSimpleName());
private static final ConcurrentHashMap<ClientLevel, ClientLevelWrapper>
levelWrapperMap = new ConcurrentHashMap<>();
public static ClientLevelWrapper getWrapper(ClientLevel level) {
return levelWrapperMap.computeIfAbsent(level, ClientLevelWrapper::new);
}
public static void closeWrapper(ClientLevel level)
{
levelWrapperMap.remove(level);
}
private ClientLevelWrapper(ClientLevel level) {
this.level = level;
}
final ClientLevel level;
ClientBlockDetailMap blockMap = new ClientBlockDetailMap(this);
@Nullable
@Override
public IServerLevelWrapper tryGetServerSideWrapper() {
try {
return ServerLevelWrapper.getWrapper(MinecraftClientWrapper.INSTANCE.mc.getSingleplayerServer().getPlayerList()
.getPlayer(MinecraftClientWrapper.INSTANCE.mc.player.getUUID()).getLevel());
} catch (Exception e) {
LOGGER.error("Failed to get server side wrapper for client level {}.", level);
return null;
}
}
public static void cleanCheck() {
if (!levelWrapperMap.isEmpty()) {
LOGGER.warn("{} client levels havn't been freed!", levelWrapperMap.size());
levelWrapperMap.clear();
}
}
@Override
public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockState) {
return blockMap.getColor(((BlockStateWrapper)blockState).blockState,
(BiomeWrapper)biome, pos);
}
@Override
public IDhApiDimensionTypeWrapper getDimensionType()
{
return DimensionTypeWrapper.getDimensionTypeWrapper(level.dimensionType());
}
@Override
public EDhApiLevelType getLevelType() { return EDhApiLevelType.CLIENT_LEVEL; }
@Override
public int getBlockLight(int x, int y, int z)
{
return level.getBrightness(LightLayer.BLOCK, new BlockPos(x,y,z));
}
@Override
public int getSkyLight(int x, int y, int z)
{
return level.getBrightness(LightLayer.SKY, new BlockPos(x,y,z));
}
public ClientLevel getLevel()
{
return level;
}
@Override
public boolean hasCeiling() {
return level.dimensionType().hasCeiling();
}
@Override
public boolean hasSkyLight() {
return level.dimensionType().hasSkyLight();
}
@Override
public int getHeight() {
return level.getHeight();
}
@Override
public int getMinHeight()
{
#if PRE_MC_1_17_1
return 0;
#else
return level.getMinBuildHeight();
#endif
}
@Override
public IChunkWrapper tryGetChunk(DhChunkPos pos) {
if (!level.hasChunk(pos.x, pos.z)) return null;
ChunkAccess chunk = level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.EMPTY, false);
if (chunk == null) return null;
return new ChunkWrapper(chunk, level, this);
}
@Override
public boolean hasChunkLoaded(int chunkX, int chunkZ) {
ChunkSource source = level.getChunkSource();
return source.hasChunk(chunkX, chunkZ);
}
@Override
public IBlockStateWrapper getBlockState(DhBlockPos pos) {
return BlockStateWrapper.fromBlockState(level.getBlockState(McObjectConverter.Convert(pos)));
}
@Override
public IBiomeWrapper getBiome(DhBlockPos pos) {
return BiomeWrapper.getBiomeWrapper(level.getBiome(McObjectConverter.Convert(pos)));
}
@Override
public ClientLevel getWrappedMcObject_UNSAFE()
{
return level;
}
@Override
public String toString() {
return "Wrapped{" + level.toString() + "@" + getDimensionType().getDimensionName() + "}";
}
}
@@ -1,19 +1,19 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
* 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
* it under the terms of the GNU 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.
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@@ -22,15 +22,14 @@ package com.seibel.lod.common.wrappers.world;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.seibel.lod.api.interfaces.world.IDhApiDimensionTypeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.dimension.DimensionType;
/**
*
* @author James Seibel
* @version 2022-9-16
* @version 11-21-2021
*/
public class DimensionTypeWrapper implements IDimensionTypeWrapper
{
@@ -80,28 +79,4 @@ public class DimensionTypeWrapper implements IDimensionTypeWrapper
{
return dimensionType.hasSkyLight();
}
@Override
public Object getWrappedMcObject_UNSAFE()
{
return this.dimensionType;
}
@Override
public boolean equals(Object obj)
{
if (obj.getClass() != DimensionTypeWrapper.class)
{
return false;
}
else
{
DimensionTypeWrapper other = (DimensionTypeWrapper) obj;
return other.getDimensionName().equals(this.getDimensionName());
}
}
}
@@ -1,189 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.world;
import java.io.File;
import java.util.concurrent.ConcurrentHashMap;
import com.seibel.lod.api.enums.worldGeneration.EDhApiLevelType;
import com.seibel.lod.common.wrappers.McObjectConverter;
import com.seibel.lod.common.wrappers.block.BiomeWrapper;
import com.seibel.lod.common.wrappers.block.BlockStateWrapper;
import com.seibel.lod.common.wrappers.block.cache.ServerBlockDetailMap;
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.pos.DhBlockPos;
import com.seibel.lod.core.pos.DhChunkPos;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IServerLevelWrapper;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.ChunkStatus;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
/**
*
* @version 2022-9-16
*/
public class ServerLevelWrapper implements IServerLevelWrapper
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger(ServerLevelWrapper.class.getSimpleName());
private static final ConcurrentHashMap<ServerLevel, ServerLevelWrapper>
levelWrapperMap = new ConcurrentHashMap<>();
public static ServerLevelWrapper getWrapper(ServerLevel level)
{
return levelWrapperMap.computeIfAbsent(level, ServerLevelWrapper::new);
}
public static void closeWrapper(ServerLevel level)
{
levelWrapperMap.remove(level);
}
public static void cleanCheck() {
if (!levelWrapperMap.isEmpty()) {
LOGGER.warn("{} server levels havn't been freed!", levelWrapperMap.size());
levelWrapperMap.clear();
}
}
final ServerLevel level;
ServerBlockDetailMap blockMap = new ServerBlockDetailMap(this);
public ServerLevelWrapper(ServerLevel level)
{
this.level = level;
}
@Nullable
@Override
public IClientLevelWrapper tryGetClientSideWrapper() {
try {
MinecraftClientWrapper client = MinecraftClientWrapper.INSTANCE;
return ClientLevelWrapper.getWrapper(client.mc.level);
} catch (Exception e) {
LOGGER.error("Failed to get client side wrapper for server level {}.", level);
return null;
}
}
@Override
public File getSaveFolder()
{
return level.getChunkSource().getDataStorage().dataFolder;
}
@Override
public DimensionTypeWrapper getDimensionType()
{
return DimensionTypeWrapper.getDimensionTypeWrapper(level.dimensionType());
}
@Override
public EDhApiLevelType getLevelType() { return EDhApiLevelType.CLIENT_LEVEL; }
@Override
public int getBlockLight(int x, int y, int z)
{
return level.getBrightness(LightLayer.BLOCK, new BlockPos(x,y,z));
}
@Override
public int getSkyLight(int x, int y, int z)
{
return level.getBrightness(LightLayer.SKY, new BlockPos(x,y,z));
}
public ServerLevel getLevel()
{
return level;
}
@Override
public boolean hasCeiling()
{
return level.dimensionType().hasCeiling();
}
@Override
public boolean hasSkyLight()
{
return level.dimensionType().hasSkyLight();
}
@Override
public int getHeight()
{
return level.getHeight();
}
@Override
public int getMinHeight()
{
#if PRE_MC_1_17_1
return 0;
#else
return level.getMinBuildHeight();
#endif
}
@Override
public IChunkWrapper tryGetChunk(DhChunkPos pos) {
if (!level.hasChunk(pos.x, pos.z)) return null;
ChunkAccess chunk = level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.EMPTY, false);
if (chunk == null) return null;
return new ChunkWrapper(chunk, level, this);
}
@Override
public boolean hasChunkLoaded(int chunkX, int chunkZ) {
// world.hasChunk(chunkX, chunkZ); THIS DOES NOT WORK FOR CLIENT LEVEL CAUSE MOJANG ALWAYS RETURN TRUE FOR THAT!
ChunkSource source = level.getChunkSource();
return source.hasChunk(chunkX, chunkZ);
}
@Override
public IBlockStateWrapper getBlockState(DhBlockPos pos) {
return BlockStateWrapper.fromBlockState(level.getBlockState(McObjectConverter.Convert(pos)));
}
@Override
public IBiomeWrapper getBiome(DhBlockPos pos) {
return BiomeWrapper.getBiomeWrapper(level.getBiome(McObjectConverter.Convert(pos)));
}
@Override
public ServerLevel getWrappedMcObject_UNSAFE()
{
return level;
}
@Override
public String toString() {
return "Wrapped{" + level.toString() + "@" + getDimensionType().getDimensionName() + "}";
}
}
@@ -0,0 +1,187 @@
/*
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.common.wrappers.world;
import java.io.File;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.seibel.lod.core.enums.WorldType;
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.ChunkStatus;
import org.jetbrains.annotations.Nullable;
/**
* @author James Seibel
* @author ??
* @version 11-21-2021
*/
public class WorldWrapper implements IWorldWrapper
{
private static final ConcurrentMap<LevelAccessor, WorldWrapper> worldWrapperMap = new ConcurrentHashMap<>();
private final LevelAccessor world;
public final WorldType worldType;
public WorldWrapper(LevelAccessor newWorld)
{
world = newWorld;
if (world.getClass() == ServerLevel.class)
worldType = WorldType.ServerWorld;
else if (world.getClass() == ClientLevel.class)
worldType = WorldType.ClientWorld;
else
worldType = WorldType.Unknown;
}
@Nullable
public static WorldWrapper getWorldWrapper(LevelAccessor world)
{
if (world == null) return null;
//first we check if the biome has already been wrapped
if(worldWrapperMap.containsKey(world) && worldWrapperMap.get(world) != null)
return worldWrapperMap.get(world);
//if it hasn't been created yet, we create it and save it in the map
WorldWrapper worldWrapper = new WorldWrapper(world);
worldWrapperMap.put(world, worldWrapper);
//we return the newly created wrapper
return worldWrapper;
}
public static void clearMap()
{
worldWrapperMap.clear();
}
@Override
public WorldType getWorldType()
{
return worldType;
}
@Override
public DimensionTypeWrapper getDimensionType()
{
return DimensionTypeWrapper.getDimensionTypeWrapper(world.dimensionType());
}
@Override
public int getBlockLight(int x, int y, int z)
{
return world.getBrightness(LightLayer.BLOCK, new BlockPos(x,y,z));
}
@Override
public int getSkyLight(int x, int y, int z)
{
return world.getBrightness(LightLayer.SKY, new BlockPos(x,y,z));
}
public LevelAccessor getWorld()
{
return world;
}
@Override
public boolean hasCeiling()
{
return world.dimensionType().hasCeiling();
}
@Override
public boolean hasSkyLight()
{
return world.dimensionType().hasSkyLight();
}
@Override
public int getHeight()
{
return world.getHeight();
}
@Override
public short getMinHeight()
{
return (short) world.getMinBuildHeight();
}
/** @throws UnsupportedOperationException if the WorldWrapper isn't for a ServerWorld */
@Override
public File getSaveFolder() throws UnsupportedOperationException
{
if (worldType != WorldType.ServerWorld)
throw new UnsupportedOperationException("getSaveFolder can only be called for ServerWorlds.");
ServerChunkCache chunkSource = ((ServerLevel) world).getChunkSource();
return chunkSource.getDataStorage().dataFolder;
}
/** @throws UnsupportedOperationException if the WorldWrapper isn't for a ServerWorld */
public ServerLevel getServerWorld() throws UnsupportedOperationException
{
if (worldType != WorldType.ServerWorld)
throw new UnsupportedOperationException("getSaveFolder can only be called for ServerWorlds.");
return (ServerLevel) world;
}
@Override
public int getSeaLevel()
{
// TODO this is depreciated, what should we use instead?
return world.getSeaLevel();
}
@Override
public IChunkWrapper tryGetChunk(AbstractChunkPosWrapper pos) {
ChunkAccess chunk = world.getChunk(pos.getX(), pos.getZ(), ChunkStatus.EMPTY, false);
if (chunk == null) return null;
return new ChunkWrapper(chunk, world);
}
@Override
public boolean hasChunkLoaded(int chunkX, int chunkZ) {
// world.hasChunk(chunkX, chunkZ); THIS DOES NOT WORK FOR CLIENT LEVEL CAUSE MOJANG ALWAYS RETURN TRUE FOR THAT!
ChunkSource source = world.getChunkSource();
return source.hasChunk(chunkX, chunkZ);
}
}
@@ -1,53 +1,50 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL v3 License.
*
* Copyright (C) 2021 Tom Lee (TomTheFurry)
* Copyright (C) 2020-2022 James Seibel
* Copyright (C) 2021 Tom Lee (TomTheFurry)
*
* 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
* it under the terms of the GNU 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.
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.common.wrappers.worldGeneration;
import com.seibel.lod.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
import com.seibel.lod.common.wrappers.world.ServerLevelWrapper;
import com.seibel.lod.core.level.IDhServerLevel;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.api.enums.config.ELightGenerationMode;
import com.seibel.lod.core.logging.ConfigBasedLogger;
import com.seibel.lod.core.logging.ConfigBasedSpamLogger;
import com.seibel.lod.core.pos.DhChunkPos;
import com.seibel.lod.core.util.objects.EventTimer;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
import com.seibel.lod.core.builders.lodBuilding.LodBuilderConfig;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.enums.config.LightGenerationMode;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.util.gridList.ArrayGridList;
import com.seibel.lod.core.util.objects.LodThreadFactory;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.util.LodThreadFactory;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper;
import java.util.ArrayList;
import java.util.Arrays;
import java.time.Duration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import com.seibel.lod.common.wrappers.DependencySetupDoneCheck;
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
import com.seibel.lod.common.wrappers.world.WorldWrapper;
import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.ChunkLoader;
import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.LightGetterAdaptor;
import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.LightedWorldGenRegion;
@@ -92,67 +89,133 @@ Lod Generation: 0.269023348s
public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnvionmentWrapper
{
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
public static final ConfigBasedSpamLogger PREF_LOGGER =
new ConfigBasedSpamLogger(LogManager.getLogger("LodWorldGen"),
() -> Config.Client.Advanced.Debugging.DebugSwitch.logWorldGenPerformance.get(),1);
() -> CONFIG.client().advanced().debugging().debugSwitch().getLogWorldGenPerformance(),1);
public static final ConfigBasedLogger EVENT_LOGGER =
new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"),
() -> Config.Client.Advanced.Debugging.DebugSwitch.logWorldGenEvent.get());
() -> CONFIG.client().advanced().debugging().debugSwitch().getLogWorldGenEvent());
public static final ConfigBasedLogger LOAD_LOGGER =
new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"),
() -> Config.Client.Advanced.Debugging.DebugSwitch.logWorldGenLoadEvent.get());
() -> CONFIG.client().advanced().debugging().debugSwitch().getLogWorldGenLoadEvent());
//TODO: Make actual proper support for StarLight
public static class PrefEvent
{
long beginNano = 0;
long emptyNano = 0;
long structStartNano = 0;
long structRefNano = 0;
long biomeNano = 0;
long noiseNano = 0;
long surfaceNano = 0;
long carverNano = 0;
long featureNano = 0;
long lightNano = 0;
long endNano = 0;
@Override
public String toString()
{
return "beginNano: " + beginNano + ",\n" +
"emptyNano: " + emptyNano + ",\n" +
"structStartNano: " + structStartNano + ",\n" +
"structRefNano: " + structRefNano + ",\n" +
"biomeNano: " + biomeNano + ",\n" +
"noiseNano: " + noiseNano + ",\n" +
"surfaceNano: " + surfaceNano + ",\n" +
"carverNano: " + carverNano + ",\n" +
"featureNano: " + featureNano + ",\n" +
"lightNano: " + lightNano + ",\n" +
"endNano: " + endNano + "\n";
}
}
public static class PerfCalculator
{
private static final String[] TIME_NAMES = {
"total",
"setup",
"structStart",
"structRef",
"biome",
"noise",
"surface",
"carver",
"feature",
"light",
"cleanup",
//"lodCreation" (No longer used)
};
public static final int SIZE = 50;
ArrayList<Rolling> times = new ArrayList<>();
public PerfCalculator()
{
for(int i = 0; i < 11; i++)
{
times.add(new Rolling(SIZE));
}
}
Rolling totalTime = new Rolling(SIZE);
Rolling emptyTime = new Rolling(SIZE);
Rolling structStartTime = new Rolling(SIZE);
Rolling structRefTime = new Rolling(SIZE);
Rolling biomeTime = new Rolling(SIZE);
Rolling noiseTime = new Rolling(SIZE);
Rolling surfaceTime = new Rolling(SIZE);
Rolling carverTime = new Rolling(SIZE);
Rolling featureTime = new Rolling(SIZE);
Rolling lightTime = new Rolling(SIZE);
Rolling lodTime = new Rolling(SIZE);
public void recordEvent(EventTimer event)
public void recordEvent(PrefEvent e)
{
for (EventTimer.Event e : event.events)
long preTime = e.beginNano;
totalTime.add(e.endNano - preTime);
if (e.emptyNano != 0)
{
String name = e.name;
int index = Arrays.asList(TIME_NAMES).indexOf(name);
if(index == -1) continue;
times.get(index).add(e.timeNs);
emptyTime.add(e.emptyNano - preTime);
preTime = e.emptyNano;
}
if (e.structStartNano != 0)
{
structStartTime.add(e.structStartNano - preTime);
preTime = e.structStartNano;
}
if (e.structRefNano != 0)
{
structRefTime.add(e.structRefNano - preTime);
preTime = e.structRefNano;
}
if (e.biomeNano != 0)
{
biomeTime.add(e.biomeNano - preTime);
preTime = e.biomeNano;
}
if (e.noiseNano != 0)
{
noiseTime.add(e.noiseNano - preTime);
preTime = e.noiseNano;
}
if (e.surfaceNano != 0)
{
surfaceTime.add(e.surfaceNano - preTime);
preTime = e.surfaceNano;
}
if (e.carverNano != 0)
{
carverTime.add(e.carverNano - preTime);
preTime = e.carverNano;
}
if (e.featureNano != 0)
{
featureTime.add(e.featureNano - preTime);
preTime = e.featureNano;
}
if (e.lightNano != 0)
{
lightTime.add(e.lightNano - preTime);
preTime = e.lightNano;
}
if (e.endNano != 0)
{
lodTime.add(e.endNano - preTime);
}
times.get(0).add(event.getTotalTimeNs());
}
public String toString()
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < times.size(); i++)
{
if (times.get(i).getAverage() == 0) continue;
sb.append(TIME_NAMES[i]).append(": ").append(times.get(i).getAverage()).append("\n");
}
return sb.toString();
return "Total: " + Duration.ofNanos((long) totalTime.getAverage()) + ", Empty/LoadChunk: "
+ Duration.ofNanos((long) emptyTime.getAverage()) + ", StructStart: "
+ Duration.ofNanos((long) structStartTime.getAverage()) + ", StructRef: "
+ Duration.ofNanos((long) structRefTime.getAverage()) + ", Biome: "
+ Duration.ofNanos((long) biomeTime.getAverage()) + ", Noise: "
+ Duration.ofNanos((long) noiseTime.getAverage()) + ", Surface: "
+ Duration.ofNanos((long) surfaceTime.getAverage()) + ", Carver: "
+ Duration.ofNanos((long) carverTime.getAverage()) + ", Feature: "
+ Duration.ofNanos((long) featureTime.getAverage()) + ", Light: "
+ Duration.ofNanos((long) lightTime.getAverage()) + ", Lod: "
+ Duration.ofNanos((long) lodTime.getAverage());
}
}
@@ -171,7 +234,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
public final StepLight stepLight = new StepLight(this);
public boolean unsafeThreadingRecorded = false;
//public boolean safeMode = false;
//private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
public static final long EXCEPTION_TIMER_RESET_TIME = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS);
public static final int EXCEPTION_COUNTER_TRIGGER = 20;
public static final int RANGE_TO_RANGE_EMPTY_EXTENSION = 1;
@@ -191,8 +254,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
}
public ExecutorService executors = Executors.newFixedThreadPool(
Math.max(Config.Client.Advanced.Threading.numberOfWorldGenerationThreads.get().intValue(), 1),
threadFactory);
CONFIG.client().advanced().threading().getNumberOfWorldGenerationThreads(), threadFactory);
public <T> T joinSync(CompletableFuture<T> f) {
if (!unsafeThreadingRecorded && !f.isDone()) {
@@ -208,7 +270,23 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
executors = Executors.newFixedThreadPool(newThreadCount,
new LodThreadFactory("Gen-Worker-Thread", Thread.MIN_PRIORITY));
}
public boolean tryAddPoint(int px, int pz, int range, Steps target, boolean genAllDetails)
{
int boxSize = range * 2 + 1;
int x = Math.floorDiv(px, boxSize) * boxSize + range;
int z = Math.floorDiv(pz, boxSize) * boxSize + range;
for (GenerationEvent event : events)
{
if (event.tooClose(x, z, range))
return false;
}
// System.out.println(x + ", "+z);
events.add(new GenerationEvent(new ChunkPos(x, z), range, this, target, genAllDetails));
return true;
}
public void updateAllFutures()
{
if (unknownExceptionCount > 0) {
@@ -216,32 +294,36 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
unknownExceptionCount = 0;
}
}
// Update all current out standing jobs
Iterator<GenerationEvent> iter = events.iterator();
while (iter.hasNext())
{
GenerationEvent event = iter.next();
if (event.future.isDone())
if (event.isCompleted())
{
if (event.future.isCompletedExceptionally() && !event.future.isCancelled()) {
try {
event.future.get(); // Should throw exception
LodUtil.assertNotReach();
} catch (Exception e) {
unknownExceptionCount++;
lastExceptionTriggerTime = System.nanoTime();
EVENT_LOGGER.error("Batching World Generator: Event {} gotten an exception", event);
EVENT_LOGGER.error("Exception: ", e);
}
try
{
event.join();
}
catch (Throwable e)
{
EVENT_LOGGER.error("Batching World Generator: Event {} gotten an exception", event);
EVENT_LOGGER.error("Exception: ", e);
unknownExceptionCount++;
lastExceptionTriggerTime = System.nanoTime();
}
finally
{
iter.remove();
}
iter.remove();
}
else if (event.hasTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS))
{
EVENT_LOGGER.error("Batching World Generator: " + event + " timed out and terminated!");
EVENT_LOGGER.info("Dump PrefEvent: " + event.timer);
try {
EVENT_LOGGER.info("Dump PrefEvent: " + event.pEvent);
try
{
if (!event.terminate())
EVENT_LOGGER.error("Failed to terminate the stuck generation event!");
}
@@ -251,31 +333,25 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
}
}
}
if (unknownExceptionCount > EXCEPTION_COUNTER_TRIGGER) {
EVENT_LOGGER.error("Too many exceptions in Batching World Generator! Disabling the generator.");
unknownExceptionCount = 0;
Config.Client.WorldGenerator.enableDistantGeneration.set(false);
CONFIG.client().worldGenerator().setEnableDistantGeneration(false);
}
}
public BatchGenerationEnvironment(IDhServerLevel serverlevel)
public BatchGenerationEnvironment(IWorldWrapper serverlevel, LodBuilder lodBuilder, LodDimension lodDim)
{
super(serverlevel);
super(serverlevel, lodBuilder, lodDim);
EVENT_LOGGER.info("================WORLD_GEN_STEP_INITING=============");
ChunkGenerator generator = ((ServerLevelWrapper) (serverlevel.getServerLevelWrapper())).getLevel().getChunkSource().getGenerator();
ChunkGenerator generator = ((WorldWrapper) serverlevel).getServerWorld().getChunkSource().getGenerator();
if (!(generator instanceof NoiseBasedChunkGenerator ||
generator instanceof DebugLevelSource ||
generator instanceof FlatLevelSource)) {
if (generator.getClass().toString().equals("class com.terraforged.mod.chunk.TFChunkGenerator")) {
EVENT_LOGGER.info("TerraForge Chunk Generator detected: [{}], Distant Generation will try its best to support it.", generator.getClass());
EVENT_LOGGER.info("If it does crash, set Distant Generation to OFF or Generation Mode to None.");
} else {
EVENT_LOGGER.warn("Unknown Chunk Generator detected: [{}], Distant Generation May Fail!", generator.getClass());
EVENT_LOGGER.warn("If it does crash, set Distant Generation to OFF or Generation Mode to None.");
}
EVENT_LOGGER.warn("Unknown Chunk Generator detected: [{}], Distant Generation May Fail!", generator.getClass());
EVENT_LOGGER.warn("If it does crash, set Distant Generation to OFF or Generation Mode to None.");
}
params = new GlobalParameters(serverlevel);
params = new GlobalParameters((ServerLevel) ((WorldWrapper) serverlevel).getWorld(), lodBuilder, lodDim);
}
@SuppressWarnings("resource")
@@ -284,11 +360,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
CompoundTag chunkData = null;
try
{
#if POST_MC_1_19
chunkData = level.getChunkSource().chunkMap.readChunk(chunkPos).get().orElse(null);
#else
chunkData = level.getChunkSource().chunkMap.readChunk(chunkPos);
#endif
}
catch (Exception e)
{
@@ -296,10 +368,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
}
if (chunkData == null)
{
return new ProtoChunk(chunkPos, UpgradeData.EMPTY
#if POST_MC_1_17_1, level #endif
#if POST_MC_1_18_1, level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null #endif
);
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null);
}
else
{
@@ -307,10 +376,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
return ChunkLoader.read(level, lightEngine, chunkPos, chunkData);
} catch (Exception e) {
LOAD_LOGGER.error("DistantHorizons: Couldn't load chunk {}", chunkPos, e);
return new ProtoChunk(chunkPos, UpgradeData.EMPTY
#if POST_MC_1_17_1, level #endif
#if POST_MC_1_18_1, level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null #endif
);
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null);
}
}
@@ -318,17 +384,17 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
public void generateLodFromList(GenerationEvent e)
{
EVENT_LOGGER.debug("Lod Generate Event: " + e.minPos);
EVENT_LOGGER.debug("Lod Generate Event: " + e.pos);
e.pEvent.beginNano = System.nanoTime();
ArrayGridList<ChunkAccess> referencedChunks;
ArrayGridList<ChunkAccess> genChunks;
EDhApiDistantGeneratorMode generatorDetail;
DistanceGenerationMode generationMode;
LightedWorldGenRegion region;
WorldGenLevelLightEngine lightEngine;
LightGetterAdaptor adaptor;
int refSize = e.size+2; // +2 for the border referenced chunks
int refPosX = e.minPos.x - 1; // -1 for the border referenced chunks
int refPosZ = e.minPos.z - 1; // -1 for the border referenced chunks
int refRange = e.range + RANGE_TO_RANGE_EMPTY_EXTENSION;
int refOffsetX = e.pos.x - refRange;
int refOffsetZ = e.pos.z - refRange;
try
{
adaptor = new LightGetterAdaptor(params.level);
@@ -348,83 +414,107 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
// Continue...
}
if (target == null)
target = new ProtoChunk(chunkPos, UpgradeData.EMPTY
#if POST_MC_1_17_1, params.level #endif
#if POST_MC_1_18_1, params.biomes, null #endif
);
target = new ProtoChunk(chunkPos, UpgradeData.EMPTY, params.level,
params.biomes, null);
return target;
};
referencedChunks = new ArrayGridList<>(refSize,
(x,z) -> generator.generate(x + refPosX,z + refPosZ)
referencedChunks = new ArrayGridList<>(refRange*2+1,
(x,z) -> generator.generate(x + refOffsetX,z + refOffsetZ)
);
e.pEvent.emptyNano = System.nanoTime();
e.refreshTimeout();
region = new LightedWorldGenRegion(params.level, lightEngine, referencedChunks,
ChunkStatus.STRUCTURE_STARTS, refSize/2, e.lightMode, generator);
ChunkStatus.STRUCTURE_STARTS, refRange, e.lightMode, generator);
adaptor.setRegion(region);
e.tParam.makeStructFeat(region, params);
genChunks = new ArrayGridList<>(referencedChunks, RANGE_TO_RANGE_EMPTY_EXTENSION,
referencedChunks.gridSize - RANGE_TO_RANGE_EMPTY_EXTENSION);
generateDirect(e, genChunks, e.target, region);
e.timer.nextEvent("cleanup");
}
catch (StepStructureStart.StructStartCorruptedException f)
{
e.tParam.markAsInvalid();
throw (RuntimeException)f.getCause();
return;
}
switch (e.target)
{
case Empty:
case StructureStart:
case StructureReference:
generationMode = DistanceGenerationMode.NONE;
break;
case Biomes:
generationMode = DistanceGenerationMode.BIOME_ONLY;
case Noise:
generationMode = DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT;
break;
case Surface:
case Carvers:
generationMode = DistanceGenerationMode.SURFACE;
break;
case Features:
generationMode = DistanceGenerationMode.FEATURES;
break;
case Light:
case LiquidCarvers:
default:
return;
}
for (int oy = 0; oy < genChunks.gridSize; oy++)
{
for (int ox = 0; ox < genChunks.gridSize; ox++)
{
ChunkAccess target = genChunks.get(ox, oy);
ChunkWrapper wrappedChunk = new ChunkWrapper(target, region, null);
ChunkWrapper wrappedChunk = new ChunkWrapper(target, region);
if (!wrappedChunk.isLightCorrect()) {
throw new RuntimeException("The generated chunk somehow has isLightCorrect() returning false");
}
boolean isFull = target.getStatus() == ChunkStatus.FULL || target instanceof LevelChunk;
#if POST_MC_1_18_1
boolean isPartial = target.isOldNoiseGeneration();
#endif
if (isFull)
{
LOAD_LOGGER.info("Detected full existing chunk at {}", target.getPos());
e.resultConsumer.accept(wrappedChunk);
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk,
new LodBuilderConfig(DistanceGenerationMode.FULL), true, e.genAllDetails);
}
#if POST_MC_1_18_1
else if (isPartial)
{
LOAD_LOGGER.info("Detected old existing chunk at {}", target.getPos());
e.resultConsumer.accept(wrappedChunk);
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk,
new LodBuilderConfig(generationMode), true, e.genAllDetails);
}
#endif
else if (target.getStatus() == ChunkStatus.EMPTY)
else if (target.getStatus() == ChunkStatus.EMPTY && generationMode == DistanceGenerationMode.NONE)
{
e.resultConsumer.accept(wrappedChunk);
params.lodBuilder.generateLodNodeFromChunk(params.lodDim,wrappedChunk,
LodBuilderConfig.getFillVoidConfig(), true, e.genAllDetails);
}
else
{
e.resultConsumer.accept(wrappedChunk);
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk,
new LodBuilderConfig(generationMode), true, e.genAllDetails);
}
if (e.lightMode == ELightGenerationMode.FANCY || isFull)
if (e.lightMode == LightGenerationMode.FANCY || isFull)
{
lightEngine.retainData(target.getPos(), false);
}
}
}
e.timer.complete();
e.pEvent.endNano = System.nanoTime();
e.refreshTimeout();
if (PREF_LOGGER.canMaybeLog())
{
e.tParam.perf.recordEvent(e.timer);
PREF_LOGGER.infoInc("{}", e.timer);
e.tParam.perf.recordEvent(e.pEvent);
PREF_LOGGER.infoInc("{}", e.tParam.perf);
}
}
public void generateDirect(GenerationEvent e, ArrayGridList<ChunkAccess> subRange,
Steps step, LightedWorldGenRegion region)
public void generateDirect(GenerationEvent e, ArrayGridList<ChunkAccess> subRange, Steps step,
LightedWorldGenRegion region)
{
try
{
@@ -438,41 +528,39 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
});
if (step == Steps.Empty)
return;
e.timer.nextEvent("structStart");
stepStructureStart.generateGroup(e.tParam, region, subRange);
e.pEvent.structStartNano = System.nanoTime();
e.refreshTimeout();
if (step == Steps.StructureStart)
return;
e.timer.nextEvent("structRef");
stepStructureReference.generateGroup(e.tParam, region, subRange);
e.pEvent.structRefNano = System.nanoTime();
e.refreshTimeout();
if (step == Steps.StructureReference)
return;
e.timer.nextEvent("biome");
stepBiomes.generateGroup(e.tParam, region, subRange);
e.pEvent.biomeNano = System.nanoTime();
e.refreshTimeout();
if (step == Steps.Biomes)
return;
e.timer.nextEvent("noise");
stepNoise.generateGroup(e.tParam, region, subRange);
e.pEvent.noiseNano = System.nanoTime();
e.refreshTimeout();
if (step == Steps.Noise)
return;
e.timer.nextEvent("surface");
stepSurface.generateGroup(e.tParam, region, subRange);
e.pEvent.surfaceNano = System.nanoTime();
e.refreshTimeout();
if (step == Steps.Surface)
return;
e.timer.nextEvent("carver");
if (step == Steps.Carvers)
return;
e.timer.nextEvent("feature");
stepFeatures.generateGroup(e.tParam, region, subRange);
e.pEvent.featureNano = System.nanoTime();
e.refreshTimeout();
}
finally
{
e.timer.nextEvent("light");
switch (region.lightMode)
{
case FANCY:
@@ -483,15 +571,14 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
{
if (p instanceof ProtoChunk)
((ProtoChunk) p).setLightCorrect(true);
#if POST_MC_1_18_1
if (p instanceof LevelChunk) {
((LevelChunk) p).setLightCorrect(true);
((LevelChunk) p).setClientLightReady(true);
}
#endif
});
break;
}
e.pEvent.lightNano = System.nanoTime();
e.refreshTimeout();
}
}
@@ -510,13 +597,6 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
public void stop(boolean blocking) {
EVENT_LOGGER.info("Batch Chunk Generator shutting down...");
executors.shutdownNow();
Iterator<GenerationEvent> iter = events.iterator();
while (iter.hasNext())
{
GenerationEvent event = iter.next();
event.future.cancel(true);
iter.remove();
}
if (blocking) try {
if (!executors.awaitTermination(10, TimeUnit.SECONDS)) {
EVENT_LOGGER.error("Batch Chunk Generator shutdown failed! Ignoring child threads...");
@@ -525,13 +605,4 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
EVENT_LOGGER.error("Batch Chunk Generator shutdown failed! Ignoring child threads...", e);
}
}
@Override
public CompletableFuture<Void> generateChunks(int minX, int minZ, int genSize, Steps targetStep, double runTimeRatio, Consumer<IChunkWrapper> resultConsumer)
{
// TODO: Check event overlap via e.tooClose()
GenerationEvent e = GenerationEvent.startEvent(new DhChunkPos(minX, minZ), genSize, this, targetStep, runTimeRatio, resultConsumer);
events.add(e);
return e.future;
}
}
@@ -1,144 +1,111 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration;
import java.lang.invoke.MethodHandles;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import com.seibel.lod.core.util.objects.UncheckedInterruptedException;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.api.enums.config.ELightGenerationMode;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.pos.DhChunkPos;
import com.seibel.lod.core.util.objects.EventTimer;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment.PrefEvent;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.enums.config.LightGenerationMode;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper.Steps;
import org.apache.logging.log4j.Logger;
import net.minecraft.world.level.ChunkPos;
//======================= Main Event class======================
public final class GenerationEvent
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
static private final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
private static int generationFutureDebugIDs = 0;
final int id;
final ThreadedParameters tParam;
final DhChunkPos minPos;
final int size;
final ChunkPos pos;
final int range;
final Future<?> future;
long nanotime;
final int id;
final Steps target;
final ELightGenerationMode lightMode;
final double runTimeRatio;
EventTimer timer = null;
long inQueueTime;
long timeoutTime = -1;
public CompletableFuture<Void> future = null;
final Consumer<IChunkWrapper> resultConsumer;
public GenerationEvent(DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup,
Steps target, double runTimeRatio, Consumer<IChunkWrapper> resultConsumer) {
inQueueTime = System.nanoTime();
this.id = generationFutureDebugIDs++;
this.minPos = minPos;
this.size = size;
final LightGenerationMode lightMode;
final PrefEvent pEvent = new PrefEvent();
final boolean genAllDetails;
public GenerationEvent(ChunkPos pos, int range, BatchGenerationEnvironment generationGroup, Steps target, boolean genAllDetails)
{
nanotime = System.nanoTime();
this.pos = pos;
this.range = range;
id = generationFutureDebugIDs++;
this.target = target;
this.tParam = ThreadedParameters.getOrMake(generationGroup.params);
this.lightMode = Config.Client.WorldGenerator.lightGenerationMode.get();
this.runTimeRatio = runTimeRatio;
this.resultConsumer = resultConsumer;
LightGenerationMode mode = CONFIG.client().worldGenerator().getLightGenerationMode();
this.lightMode = mode;
this.genAllDetails = genAllDetails;
future = generationGroup.executors.submit(() ->
{
BatchGenerationEnvironment.isDistantGeneratorThread.set(true);
try {
generationGroup.generateLodFromList(this);
} finally {
BatchGenerationEnvironment.isDistantGeneratorThread.remove();
}
});
}
public static GenerationEvent startEvent(DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup,
Steps target, double runTimeRatio, Consumer<IChunkWrapper> resultConsumer)
{
if (size % 2 == 0) size += 1; // size must be odd for vanilla world gen region to work
GenerationEvent event = new GenerationEvent(minPos, size, generationGroup, target, runTimeRatio, resultConsumer);
event.future = CompletableFuture.runAsync(() ->
{
long runStartTime = System.nanoTime();
event.timeoutTime = runStartTime;
event.inQueueTime = runStartTime - event.inQueueTime;
event.timer = new EventTimer("setup");
BatchGenerationEnvironment.isDistantGeneratorThread.set(true);
try {
generationGroup.generateLodFromList(event);
} finally {
BatchGenerationEnvironment.isDistantGeneratorThread.remove();
if (!Thread.interrupted() && runTimeRatio < 1.0) {
long endTime = System.nanoTime();
try {
long deltaMs = TimeUnit.NANOSECONDS.toMillis(endTime - runStartTime);
Thread.sleep((long) (deltaMs/runTimeRatio - deltaMs));
} catch (InterruptedException ignored) {}
}
}
}, generationGroup.executors);
return event;
}
public boolean isComplete()
public boolean isCompleted()
{
return future.isDone();
}
public boolean hasTimeout(int duration, TimeUnit unit)
{
if (timeoutTime == -1) return false;
long currentTime = System.nanoTime();
long delta = currentTime - timeoutTime;
long delta = currentTime - nanotime;
return (delta > TimeUnit.NANOSECONDS.convert(duration, unit));
}
public boolean terminate()
{
LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN=======================");
ApiShared.LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN=======================");
BatchGenerationEnvironment.threadFactory.dumpAllThreadStacks();
future.cancel(true);
return future.isCancelled();
}
public boolean tooClose(int minX, int minZ, int w)
public void join()
{
int aMinX = minPos.x;
int aMinZ = minPos.z;
int aSize = size;
// Account for required empty chunks in the border
aSize += 1;
w+= 1;
// Do a AABB to AABB intersection test
return (aMinX + aSize >= minX &&
aMinX <= minX + w &&
aMinZ + aSize >= minZ &&
aMinZ <= minZ + w);
try
{
future.get();
}
catch (InterruptedException | ExecutionException e)
{
throw new RuntimeException(e.getCause()==null? e : e.getCause());
}
}
public boolean tooClose(int cx, int cz, int cr)
{
int distX = Math.abs(cx - pos.x);
int distZ = Math.abs(cz - pos.z);
int minRange = cr + range + 1; // Need one to account for the center
minRange += 1 + 1; // Account for required empty chunks
return distX < minRange && distZ < minRange;
}
public void refreshTimeout()
{
timeoutTime = System.nanoTime();
UncheckedInterruptedException.throwIfInterrupted();
nanotime = System.nanoTime();
LodUtil.checkInterruptsUnchecked();
}
@Override
public String toString()
{
return id + ":" + size + "@" + minPos + "(" + target + ")";
return id + ":" + range + "@" + pos + "(" + target + ")";
}
}
@@ -1,27 +1,9 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration;
import com.mojang.datafixers.DataFixer;
import com.seibel.lod.common.wrappers.world.ServerLevelWrapper;
import com.seibel.lod.core.level.IDhServerLevel;
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
import com.seibel.lod.core.objects.lod.LodDimension;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
@@ -31,45 +13,32 @@ import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.chunk.ChunkGenerator;
#if POST_MC_1_18_1
import net.minecraft.world.level.chunk.storage.ChunkScanAccess;
#endif
import net.minecraft.world.level.levelgen.WorldGenSettings;
#if PRE_MC_1_19
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
#else
import net.minecraft.world.level.levelgen.RandomState;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
#endif
import net.minecraft.world.level.storage.WorldData;
public final class GlobalParameters
{
public final ChunkGenerator generator;
#if PRE_MC_1_19
public final StructureManager structures;
#else
public final StructureTemplateManager structures;
public final RandomState randomState;
#endif
public final BiomeManager biomeManager;
public final WorldGenSettings worldGenSettings;
public final ThreadedLevelLightEngine lightEngine;
public final IDhServerLevel lodLevel;
public final ServerLevel level;
public final LodBuilder lodBuilder;
public final LodDimension lodDim;
public final Registry<Biome> biomes;
public final RegistryAccess registry;
public final long worldSeed;
public final ChunkScanAccess chunkScanner;
public final ServerLevel level; // TODO: Figure out a way to remove this. Maybe ClientLevel also works?
public final DataFixer fixerUpper;
#if POST_MC_1_18_1
public final BiomeManager biomeManager;
public final ChunkScanAccess chunkScanner; // FIXME: Figure out if this is actually needed
#endif
public GlobalParameters(IDhServerLevel lodLevel)
public GlobalParameters(ServerLevel level, LodBuilder lodBuilder, LodDimension lodDim)
{
this.lodLevel = lodLevel;
level = ((ServerLevelWrapper)lodLevel.getServerLevelWrapper()).getWrappedMcObject_UNSAFE();
this.lodBuilder = lodBuilder;
this.lodDim = lodDim;
this.level = level;
lightEngine = (ThreadedLevelLightEngine) level.getLightEngine();
MinecraftServer server = level.getServer();
WorldData worldData = server.getWorldData();
@@ -77,15 +46,10 @@ public final class GlobalParameters
registry = server.registryAccess();
biomes = registry.registryOrThrow(Registry.BIOME_REGISTRY);
worldSeed = worldGenSettings.seed();
#if POST_MC_1_18_1
biomeManager = new BiomeManager(level, BiomeManager.obfuscateSeed(worldSeed));
chunkScanner = level.getChunkSource().chunkScanner();
#endif
structures = server.getStructureManager();
generator = level.getChunkSource().getGenerator();
chunkScanner = level.getChunkSource().chunkScanner();
fixerUpper = server.getFixerUpper();
#if POST_MC_1_19
randomState = level.getChunkSource().randomState();
#endif
}
}
@@ -1,22 +1,3 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration;
@@ -48,6 +29,6 @@ public class Rolling
public double getAverage()
{
return size==0 ? 0 : total / size;
return total / size;
}
}
@@ -1,22 +1,3 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration;
@@ -26,18 +7,14 @@ import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.WorldGenStruct
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.levelgen.WorldGenSettings;
#if POST_MC_1_18_1
import net.minecraft.world.level.levelgen.structure.StructureCheck;
#endif
public final class ThreadedParameters
{
private static final ThreadLocal<ThreadedParameters> localParam = new ThreadLocal<ThreadedParameters>();
final ServerLevel level;
public WorldGenStructFeatManager structFeat = null;
#if POST_MC_1_18_1
public final StructureCheck structCheck;
#endif
boolean isValid = true;
public final PerfCalculator perf = new PerfCalculator();
@@ -59,21 +36,13 @@ public final class ThreadedParameters
private ThreadedParameters(GlobalParameters param)
{
level = param.level;
#if PRE_MC_1_18_1
structFeat = new WorldGenStructFeatManager(param.worldGenSettings, level);
#elif PRE_MC_1_19
structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
param.level.dimension(), param.generator, level, param.generator.getBiomeSource(), param.worldSeed,
param.fixerUpper);
#else
structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
param.level.dimension(), param.generator, param.randomState, level, param.generator.getBiomeSource(), param.worldSeed,
param.fixerUpper);
#endif
}
public void makeStructFeat(WorldGenLevel genLevel, GlobalParameters param)
{
structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel #if POST_MC_1_18_1, structCheck #endif);
structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel, structCheck);
}
}
@@ -1,32 +1,26 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration.mimicObject;
import com.google.common.collect.Maps;
import com.mojang.serialization.Codec;
import com.mojang.serialization.Dynamic;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.logging.ConfigBasedLogger;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
#if MC_VERSION_1_18_2
import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
#endif
import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
@@ -34,41 +28,40 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.*;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.*;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.DataLayer;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.levelgen.Heightmap;
#if POST_MC_1_18_1
import net.minecraft.world.level.levelgen.blending.BlendingData;
import net.minecraft.world.ticks.LevelChunkTicks;
#endif
#if POST_MC_1_18_2
import net.minecraft.core.Holder;
#endif
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.level.levelgen.structure.StructureStart;
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceSerializationContext;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.ticks.LevelChunkTicks;
import org.apache.logging.log4j.Logger;
public class ChunkLoader
{
#if POST_MC_1_19
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
#elif POST_MC_1_18_1
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
#endif
private static final String TAG_UPGRADE_DATA = "UpgradeData";
private static final String BLOCK_TICKS_TAG_18 = "block_ticks";
private static final String FLUID_TICKS_TAG_18 = "fluid_ticks";
private static final String BLOCK_TICKS_TAG_PRE18 = "TileTicks";
private static final String FLUID_TICKS_TAG_PRE18 = "LiquidTicks";
private static final ConfigBasedLogger LOGGER = BatchGenerationEnvironment.LOAD_LOGGER;
#if POST_MC_1_18_1
private static final String TAG_UPGRADE_DATA = "UpgradeData";
private static final String BLOCK_TICKS_TAG = "block_ticks";
private static final String FLUID_TICKS_TAG = "fluid_ticks";
private static BlendingData readBlendingData(CompoundTag chunkData)
{
BlendingData blendingData = null;
@@ -80,54 +73,36 @@ public class ChunkLoader
}
return blendingData;
}
#endif
private static LevelChunkSection[] readSections(LevelAccessor level, LevelLightEngine lightEngine, ChunkPos chunkPos, CompoundTag chunkData)
{
#if POST_MC_1_18_1
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
#if PRE_MC_1_18_2
Codec<PalettedContainer<Biome>> biomeCodec = PalettedContainer.codec(
biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
#elif PRE_MC_1_19
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codec(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
#else
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
#endif
#if MC_VERSION_1_18_1
Codec<PalettedContainer<Biome>> biomeCodec = PalettedContainer.codec(
biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
#elif MC_VERSION_1_18_2
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codec(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
#endif
int i = #if PRE_MC_1_17_1 16; #else level.getSectionsCount(); #endif
int i = level.getSectionsCount();
LevelChunkSection[] chunkSections = new LevelChunkSection[i];
boolean isLightOn = chunkData.getBoolean("isLightOn");
boolean hasSkyLight = level.dimensionType().hasSkyLight();
ListTag tagSections = chunkData.getList("Sections", 10);
if (tagSections.isEmpty()) tagSections = chunkData.getList("sections", 10);
ListTag tagSections = chunkData.getList("sections", 10);
for (int j = 0; j < tagSections.size(); ++j)
{
CompoundTag tagSection = tagSections.getCompound(j);
int sectionYPos = tagSection.getByte("Y");
#if PRE_MC_1_18_1
if (tagSection.contains("Palette", 9) && tagSection.contains("BlockStates", 12)) {
LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4);
levelChunkSection.getStates().read(tagSection.getList("Palette", 10),
tagSection.getLongArray("BlockStates"));
levelChunkSection.recalcBlockCounts();
if (!levelChunkSection.isEmpty())
chunkSections[#if PRE_MC_1_17_1 sectionYPos #else level.getSectionIndexFromSectionY(sectionYPos) #endif]
= levelChunkSection;
}
#else
byte sectionYPos = tagSection.getByte("Y");
int sectionId = level.getSectionIndexFromSectionY(sectionYPos);
if (sectionId >= 0 && sectionId < chunkSections.length)
{
PalettedContainer<BlockState> blockStateContainer;
#if PRE_MC_1_18_2
#if MC_VERSION_1_18_1
PalettedContainer<Biome> biomeContainer;
#else
#elif MC_VERSION_1_18_2
PalettedContainer<Holder<Biome>> biomeContainer;
#endif
@@ -135,26 +110,27 @@ public class ChunkLoader
? BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagSection.getCompound("block_states")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, LOGGER::error)
: new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
#if PRE_MC_1_18_2
#if MC_VERSION_1_18_1
biomeContainer = tagSection.contains("biomes", 10)
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, LOGGER::error)
: new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
#else
#elif MC_VERSION_1_18_2
biomeContainer = tagSection.contains("biomes", 10)
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, i, (String) string)).getOrThrow(false, LOGGER::error)
: new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(), biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
#endif
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
}
#endif
if (!isLightOn) continue;
if (!isLightOn)
continue;
if (tagSection.contains("BlockLight", 7))
lightEngine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, sectionYPos),
new DataLayer(tagSection.getByteArray("BlockLight")), true);
lightEngine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, sectionYPos), new DataLayer(tagSection.getByteArray("BlockLight")), true);
if (hasSkyLight && tagSection.contains("SkyLight", 7))
lightEngine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkPos, sectionYPos),
new DataLayer(tagSection.getByteArray("SkyLight")), true);
lightEngine.queueSectionData(LightLayer.SKY, SectionPos.of(chunkPos, sectionYPos), new DataLayer(tagSection.getByteArray("SkyLight")), true);
}
return chunkSections;
}
@@ -171,6 +147,115 @@ public class ChunkLoader
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
}
#if MC_VERSION_1_18_1
private static Map<StructureFeature<?>, StructureStart<?>> unpackStructureStart(StructurePieceSerializationContext structurePieceSerializationContext, CompoundTag compoundTag, long l)
{
HashMap<StructureFeature<?>, StructureStart<?>> map = Maps.newHashMap();
CompoundTag compoundTag2 = compoundTag.getCompound("starts");
for (String string : compoundTag2.getAllKeys())
{
String string2 = string.toLowerCase(Locale.ROOT);
StructureFeature<?> structureFeature = StructureFeature.STRUCTURES_REGISTRY.get(string2);
if (structureFeature == null)
{
LOGGER.error("Unknown structure start: {}", (Object) string2);
continue;
}
StructureStart<?> structureStart = StructureFeature.loadStaticStart(structurePieceSerializationContext, compoundTag2.getCompound(string), l);
if (structureStart == null)
continue;
map.put(structureFeature, structureStart);
}
return map;
}
private static Map<StructureFeature<?>, LongSet> unpackStructureReferences(ChunkPos chunkPos, CompoundTag compoundTag)
{
HashMap<StructureFeature<?>, LongSet> map = Maps.newHashMap();
CompoundTag compoundTag2 = compoundTag.getCompound("References");
for (String string : compoundTag2.getAllKeys())
{
String string2 = string.toLowerCase(Locale.ROOT);
StructureFeature<?> structureFeature = StructureFeature.STRUCTURES_REGISTRY.get(string2);
if (structureFeature == null)
{
LOGGER.warn("Found reference to unknown structure '{}' in chunk {}, discarding", (Object) string2, (Object) chunkPos);
continue;
}
map.put(structureFeature, new LongOpenHashSet(Arrays.stream(compoundTag2.getLongArray(string)).filter(l ->
{
ChunkPos chunkPos2 = new ChunkPos(l);
if (chunkPos2.getChessboardDistance(chunkPos) > 8)
{
LOGGER.warn("Found invalid structure reference [ {} @ {} ] for chunk {}.", (Object) string2, (Object) chunkPos2, (Object) chunkPos);
return false;
}
return true;
}).toArray()));
}
return map;
}
#elif MC_VERSION_1_18_2
private static Map<ConfiguredStructureFeature<?, ?>, StructureStart> unpackStructureStart(StructurePieceSerializationContext structurePieceSerializationContext, CompoundTag compoundTag, long l) {
Map<ConfiguredStructureFeature<?, ?>, StructureStart> map = Maps.newHashMap();
Registry<ConfiguredStructureFeature<?, ?>> structStartRegistry = structurePieceSerializationContext.registryAccess().registryOrThrow(Registry.CONFIGURED_STRUCTURE_FEATURE_REGISTRY);
CompoundTag compoundTag2 = compoundTag.getCompound("starts");
for (String string : compoundTag2.getAllKeys()) {
ResourceLocation resourceLocation = ResourceLocation.tryParse(string);
ConfiguredStructureFeature<?, ?> structureFeature = structStartRegistry.get(resourceLocation);
// String string2 = string.toLowerCase(Locale.ROOT);
// ConfiguredStructureFeature<?, ?> structureFeature = StructureFeature.STRUCTURES_REGISTRY.get(string2);
if (structureFeature == null) {
LOGGER.error("Unknown structure start: {}", resourceLocation);
continue;
}
StructureStart structureStart = StructureFeature.loadStaticStart(structurePieceSerializationContext, compoundTag2.getCompound(string), l);
if (structureStart == null)
continue;
map.put(structureFeature, structureStart);
}
return map;
}
private static Map<ConfiguredStructureFeature<?, ?>, LongSet> unpackStructureReferences(RegistryAccess registryAccess, ChunkPos chunkPos, CompoundTag compoundTag)
{
Map<ConfiguredStructureFeature<?, ?>, LongSet> map = Maps.newHashMap();
Registry<ConfiguredStructureFeature<?, ?>> structRegistry = registryAccess.registryOrThrow(Registry.CONFIGURED_STRUCTURE_FEATURE_REGISTRY);
CompoundTag compoundTag2 = compoundTag.getCompound("References");
for (String string : compoundTag2.getAllKeys())
{
ResourceLocation resourceLocation = ResourceLocation.tryParse(string);
ConfiguredStructureFeature<?, ?> structureFeature = structRegistry.get(resourceLocation);
// String string2 = string.toLowerCase(Locale.ROOT);
// ConfiguredStructureFeature<?, ?> structureFeature = StructureFeature.STRUCTURES_REGISTRY.get(string2);
if (structureFeature == null)
{
LOGGER.warn("Found reference to unknown structure '{}' in chunk {}, discarding", resourceLocation, chunkPos);
continue;
}
map.put(structureFeature, new LongOpenHashSet(Arrays.stream(compoundTag2.getLongArray(string)).filter(l ->
{
ChunkPos chunkPos2 = new ChunkPos(l);
if (chunkPos2.getChessboardDistance(chunkPos) > 8)
{
LOGGER.warn("Found invalid structure reference [ {} @ {} ] for chunk {}.", resourceLocation, chunkPos2, chunkPos);
return false;
}
return true;
}).toArray()));
}
return map;
}
#endif
private static void readStructures(WorldGenLevel level, LevelChunk chunk, CompoundTag chunkData)
{
CompoundTag tagStructures = chunkData.getCompound("structures");
chunk.setAllStarts(
unpackStructureStart(StructurePieceSerializationContext.fromLevel(level.getLevel()), tagStructures, level.getSeed()));
chunk.setAllReferences(unpackStructureReferences(#if MC_VERSION_1_18_2 level.registryAccess() ,#endif chunk.getPos(), tagStructures));
}
private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
{
ListTag tagPostProcessings = chunkData.getList("PostProcessing", 9);
@@ -184,88 +269,49 @@ public class ChunkLoader
}
}
public static ChunkStatus.ChunkType readChunkType(CompoundTag tagLevel)
public static ChunkStatus.ChunkType readChunkType(CompoundTag compoundTag)
{
ChunkStatus chunkStatus = ChunkStatus.byName(tagLevel.getString("Status"));
if (chunkStatus != null) {
return chunkStatus.getChunkType();
}
return ChunkStatus.ChunkType.PROTOCHUNK;
return ChunkStatus.byName(compoundTag.getString("Status")).getChunkType();
}
public static LevelChunk read(WorldGenLevel level, LevelLightEngine lightEngine, ChunkPos chunkPos, CompoundTag chunkData)
{
#if PRE_MC_1_18_1
CompoundTag tagLevel = chunkData.getCompound("Level");
#else
CompoundTag tagLevel = chunkData;
#endif
ChunkPos actualPos = new ChunkPos(tagLevel.getInt("xPos"), tagLevel.getInt("zPos"));
if (!Objects.equals(chunkPos, actualPos)) {
LOGGER.error("Chunk file at {} is in the wrong location; Ignoring. (Expected {}, got {})", chunkPos, chunkPos, actualPos);
ChunkPos actualPos = new ChunkPos(chunkData.getInt("xPos"), chunkData.getInt("zPos"));
if (!Objects.equals(chunkPos, actualPos))
{
LOGGER.error("Chunk file at {} is in the wrong location; Ignoring. (Expected {}, got {})", (Object) chunkPos, (Object) chunkPos, (Object) actualPos);
return null;
}
ChunkStatus.ChunkType chunkType = readChunkType(tagLevel);
#if PRE_MC_1_18_1
if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK)
return null;
#else
BlendingData blendingData = readBlendingData(tagLevel);
#if PRE_MC_1_19
ChunkStatus.ChunkType chunkType = readChunkType(chunkData);
BlendingData blendingData = readBlendingData(chunkData);
if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || !blendingData.oldNoise()))
return null;
#else
if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || level.getChunk(chunkPos.getMiddleBlockX(),chunkPos.getMiddleBlockZ()).isOldNoiseGeneration()))
return null;
#endif
#endif
long inhabitedTime = tagLevel.getLong("InhabitedTime");
//================== Read params for making the LevelChunk ==================
UpgradeData upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
? new UpgradeData(tagLevel.getCompound(TAG_UPGRADE_DATA)#if POST_MC_1_17_1, level #endif)
// Prepare the light engine
boolean isLightOn = chunkData.getBoolean("isLightOn");
if (isLightOn)
level.getLightEngine().retainData(chunkPos, true);
// Read params for making the LevelChunk
UpgradeData upgradeData = chunkData.contains(TAG_UPGRADE_DATA, 10)
? new UpgradeData(chunkData.getCompound(TAG_UPGRADE_DATA), level)
: UpgradeData.EMPTY;
boolean isLightOn = tagLevel.getBoolean("isLightOn");
if (isLightOn) lightEngine.retainData(chunkPos, true);
#if PRE_MC_1_18_1
ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer(
level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY)#if POST_MC_1_17_1, level #endif,
chunkPos, level.getLevel().getChunkSource().getGenerator().getBiomeSource(),
tagLevel.contains("Biomes", 11) ? tagLevel.getIntArray("Biomes") : null);
TickList<Block> blockTicks = tagLevel.contains(BLOCK_TICKS_TAG_PRE18, 9)
? ChunkTickList.create(tagLevel.getList(BLOCK_TICKS_TAG_PRE18, 10), Registry.BLOCK::getKey, Registry.BLOCK::get)
: new ProtoTickList<Block>(block -> (block == null || block.defaultBlockState().isAir()), chunkPos,
tagLevel.getList("ToBeTicked", 9)#if POST_MC_1_17_1, level #endif);
TickList<Fluid> fluidTicks = tagLevel.contains(FLUID_TICKS_TAG_PRE18, 9)
? ChunkTickList.create(tagLevel.getList(FLUID_TICKS_TAG_PRE18, 10), Registry.FLUID::getKey, Registry.FLUID::get)
: new ProtoTickList<Fluid>(fluid -> (fluid == null || fluid == Fluids.EMPTY), chunkPos,
tagLevel.getList("LiquidsToBeTicked", 9)#if POST_MC_1_17_1, level #endif);
#else
LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10),
LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(chunkData.getList(BLOCK_TICKS_TAG, 10),
string -> Registry.BLOCK.getOptional(ResourceLocation.tryParse(string)), chunkPos);
LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10),
LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(chunkData.getList(FLUID_TICKS_TAG, 10),
string -> Registry.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos);
#endif
LevelChunkSection[] levelChunkSections = readSections(level, lightEngine, chunkPos, tagLevel);
// ====================== Make the chunk =========================
#if PRE_MC_1_18_1
LevelChunk chunk = new LevelChunk((Level) level.getLevel(), chunkPos, chunkBiomeContainer, upgradeData, blockTicks,
fluidTicks, inhabitedTime, levelChunkSections, null);
#else
LevelChunk chunk = new LevelChunk((Level) level, chunkPos, upgradeData, blockTicks,
fluidTicks, inhabitedTime, levelChunkSections, null, blendingData);
#endif
long inhabitedTime = chunkData.getLong("InhabitedTime");
LevelChunkSection[] chunkSections = readSections(level, lightEngine, actualPos, chunkData);
// Make chunk
LevelChunk chunk = new LevelChunk((Level) level, chunkPos, upgradeData, blockTicks, fluidTicks, inhabitedTime, chunkSections, null, blendingData);
// Set some states after object creation
chunk.setLightCorrect(isLightOn);
readHeightmaps(chunk, chunkData);
readStructures(level, chunk, chunkData);
readPostPocessings(chunk, chunkData);
return chunk;
}
@@ -1,31 +1,10 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration.mimicObject;
import com.seibel.lod.core.dependencyInjection.ModAccessorInjector;
import com.seibel.lod.core.handlers.dependencyInjection.ModAccessorHandler;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
import net.minecraft.world.level.BlockGetter;
#if POST_MC_1_17_1
import net.minecraft.world.level.LevelHeightAccessor;
#endif
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LightChunkGetter;
@@ -36,7 +15,7 @@ public class LightGetterAdaptor implements LightChunkGetter {
public LightGetterAdaptor(BlockGetter heightAccessor) {
this.heightGetter = heightAccessor;
shouldReturnNull = ModAccessorInjector.INSTANCE.get(IStarlightAccessor.class) != null;
shouldReturnNull = ModAccessorHandler.get(IStarlightAccessor.class) != null;
}
public void setRegion(LightedWorldGenRegion region) {
@@ -55,10 +34,7 @@ public class LightGetterAdaptor implements LightChunkGetter {
public BlockGetter getLevel() {
return shouldReturnNull ? null : (genRegion != null ? genRegion : heightGetter);
}
#if POST_MC_1_17_1
public LevelHeightAccessor getLevelHeightAccessor() {
return heightGetter;
}
#endif
}
@@ -1,38 +1,19 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration.mimicObject;
import java.lang.invoke.MethodHandles;
import java.util.List;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.SpawnerBlock;
import org.apache.logging.log4j.Logger;
import com.seibel.lod.core.api.ApiShared;
import org.jetbrains.annotations.Nullable;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment.EmptyChunkGenerator;
import com.seibel.lod.api.enums.config.ELightGenerationMode;
import com.seibel.lod.core.enums.config.LightGenerationMode;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.client.color.block.BlockTintCache;
import net.minecraft.client.renderer.BiomeColors;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Cursor3D;
import net.minecraft.core.SectionPos;
@@ -42,10 +23,9 @@ import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.ColorResolver;
#if POST_MC_1_17_1
import net.minecraft.world.level.LevelHeightAccessor;
#endif
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.StructureFeatureManager;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
@@ -55,47 +35,24 @@ import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ImposterProtoChunk;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.level.levelgen.structure.StructureStart;
import net.minecraft.world.level.lighting.LevelLightEngine;
public class LightedWorldGenRegion extends WorldGenRegion
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
public class LightedWorldGenRegion extends WorldGenRegion {
public final WorldGenLevelLightEngine light;
public final ELightGenerationMode lightMode;
public final LightGenerationMode lightMode;
public final EmptyChunkGenerator generator;
public final int writeRadius;
public final int size;
private final ChunkPos firstPos;
private final List<ChunkAccess> cache;
Long2ObjectOpenHashMap<ChunkAccess> chunkMap = new Long2ObjectOpenHashMap<ChunkAccess>();
#if PRE_MC_1_18_1
private ChunkPos overrideCenterPos = null;
public void setOverrideCenter(ChunkPos pos) {overrideCenterPos = pos;}
#if PRE_MC_1_17_1
@Override
public int getCenterX() {
return overrideCenterPos==null ? super.getCenterX() : overrideCenterPos.x;
}
@Override
public int getCenterZ() {
return overrideCenterPos==null ? super.getCenterX() : overrideCenterPos.z;
}
#else
@Override
public ChunkPos getCenter() {
return overrideCenterPos==null ? super.getCenter() : overrideCenterPos;
}
#endif
#endif
public LightedWorldGenRegion(ServerLevel serverLevel, WorldGenLevelLightEngine lightEngine,
List<ChunkAccess> list, ChunkStatus chunkStatus, int i,
ELightGenerationMode lightMode, EmptyChunkGenerator generator)
{
super(serverLevel, list #if POST_MC_1_17_1, chunkStatus, i #endif);
LightGenerationMode lightMode, EmptyChunkGenerator generator) {
super(serverLevel, list, chunkStatus, i);
this.lightMode = lightMode;
this.firstPos = list.get(0).getPos();
this.generator = generator;
@@ -103,13 +60,17 @@ public class LightedWorldGenRegion extends WorldGenRegion
writeRadius = i;
cache = list;
size = Mth.floor(Math.sqrt(list.size()));
this.tintCaches = Util.make(new Object2ObjectArrayMap(3), object2ObjectArrayMap -> {
object2ObjectArrayMap.put(BiomeColors.GRASS_COLOR_RESOLVER, new BlockTintCache((pos) -> {return calculateBlockTint(pos, BiomeColors.GRASS_COLOR_RESOLVER);}));
object2ObjectArrayMap.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new BlockTintCache((pos) -> {return calculateBlockTint(pos, BiomeColors.FOLIAGE_COLOR_RESOLVER);}));
object2ObjectArrayMap.put(BiomeColors.WATER_COLOR_RESOLVER, new BlockTintCache((pos) -> {return calculateBlockTint(pos, BiomeColors.WATER_COLOR_RESOLVER);}));
});
}
#if POST_MC_1_17_1
// Bypass BCLib mixin overrides.
@Override
public boolean ensureCanWrite(BlockPos blockPos)
{
public boolean ensureCanWrite(BlockPos blockPos) {
int i = SectionPos.blockToSectionCoord(blockPos.getX());
int j = SectionPos.blockToSectionCoord(blockPos.getZ());
ChunkPos chunkPos = this.getCenter();
@@ -119,17 +80,14 @@ public class LightedWorldGenRegion extends WorldGenRegion
if (k > this.writeRadius || l > this.writeRadius) {
return false;
}
#if POST_MC_1_18_1
if (center.isUpgrading()) {
LevelHeightAccessor levelHeightAccessor = center.getHeightAccessorForGeneration();
if (blockPos.getY() < levelHeightAccessor.getMinBuildHeight() || blockPos.getY() >= levelHeightAccessor.getMaxBuildHeight()) {
return false;
}
}
#endif
return true;
}
#endif
// TODO Check this
// @Override
@@ -165,18 +123,7 @@ public class LightedWorldGenRegion extends WorldGenRegion
// Skip BlockEntity stuff. It aren't really needed
@Override
public BlockEntity getBlockEntity(BlockPos blockPos) {
BlockState blockState = this.getBlockState(blockPos);
// This is a bypass for the spawner block since MC complains about not having it
#if POST_MC_1_17_1
if (blockState.getBlock() instanceof SpawnerBlock) {
return ((EntityBlock) blockState.getBlock()).newBlockEntity(blockPos, blockState);
} else return null;
#else
if (blockState.getBlock() instanceof SpawnerBlock) {
return ((EntityBlock) blockState.getBlock()).newBlockEntity(this);
} else return null;
#endif
return null;
}
// Skip BlockEntity stuff. It aren't really needed
@@ -225,7 +172,7 @@ public class LightedWorldGenRegion extends WorldGenRegion
public ChunkAccess getChunk(int i, int j, ChunkStatus chunkStatus, boolean bl) {
ChunkAccess chunk = getChunkAccess(i, j, chunkStatus, bl);
if (chunk instanceof LevelChunk) {
chunk = new ImposterProtoChunk((LevelChunk) chunk #if POST_MC_1_18_1, true #endif);
chunk = new ImposterProtoChunk((LevelChunk) chunk, true);
}
return chunk;
}
@@ -249,7 +196,7 @@ public class LightedWorldGenRegion extends WorldGenRegion
}
}
if (chunkStatus != ChunkStatus.EMPTY && chunkStatus != debugTriggeredForStatus) {
LOGGER.info("WorldGen requiring " + chunkStatus
ApiShared.LOGGER.info("WorldGen requiring " + chunkStatus
+ " outside expected range detected. Force passing EMPTY chunk and seeing if it works.");
debugTriggeredForStatus = chunkStatus;
}
@@ -265,7 +212,7 @@ public class LightedWorldGenRegion extends WorldGenRegion
// Override force use of my own light engine
@Override
public int getBrightness(LightLayer lightLayer, BlockPos blockPos) {
if (lightMode != ELightGenerationMode.FAST) {
if (lightMode != LightGenerationMode.FAST) {
return light.getLayerListener(lightLayer).getLightValue(blockPos);
}
if (lightLayer == LightLayer.BLOCK)
@@ -277,7 +224,7 @@ public class LightedWorldGenRegion extends WorldGenRegion
// Override force use of my own light engine
@Override
public int getRawBrightness(BlockPos blockPos, int i) {
if (lightMode != ELightGenerationMode.FAST) {
if (lightMode != LightGenerationMode.FAST) {
return light.getRawBrightness(blockPos, i);
}
BlockPos p = super.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, blockPos);
@@ -289,27 +236,28 @@ public class LightedWorldGenRegion extends WorldGenRegion
public boolean canSeeSky(BlockPos blockPos) {
return (getBrightness(LightLayer.SKY, blockPos) >= getMaxLightLevel());
}
private final Object2ObjectArrayMap<ColorResolver, BlockTintCache> tintCaches;
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
{
return calculateBlockTint(blockPos, colorResolver);
BlockTintCache blockTintCache = (BlockTintCache) this.tintCaches.get(colorResolver);
return blockTintCache.getColor(blockPos);
}
private Biome _getBiome(BlockPos pos) {
#if POST_MC_1_18_2
#if MC_VERSION_1_18_2
return getBiome(pos).value();
#else
#elif MC_VERSION_1_18_1
return getBiome(pos);
#endif
}
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
{
#if PRE_MC_1_19
int i = (Minecraft.getInstance()).options.biomeBlendRadius;
#else
int i = (Minecraft.getInstance()).options.biomeBlendRadius().get();
#endif
if (i == 0)
return colorResolver.getColor((Biome) _getBiome(blockPos), blockPos.getX(), blockPos.getZ());
int j = (i * 2 + 1) * (i * 2 + 1);
@@ -1,22 +1,3 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration.mimicObject;
import org.jetbrains.annotations.Nullable;
@@ -24,9 +5,7 @@ import org.jetbrains.annotations.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.ChunkPos;
#if POST_MC_1_17_1
import net.minecraft.world.level.LevelHeightAccessor;
#endif
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.DataLayer;
@@ -39,9 +18,7 @@ import net.minecraft.world.level.lighting.SkyLightEngine;
public class WorldGenLevelLightEngine extends LevelLightEngine {
public static final int MAX_SOURCE_LEVEL = 15;
public static final int LIGHT_SECTION_PADDING = 1;
#if POST_MC_1_17_1
protected final LevelHeightAccessor levelHeightAccessor;
#endif
@Nullable
public final BlockLightEngine blockEngine;
@Nullable
@@ -49,9 +26,7 @@ public class WorldGenLevelLightEngine extends LevelLightEngine {
public WorldGenLevelLightEngine(LightGetterAdaptor genRegion) {
super(genRegion, false, false);
#if POST_MC_1_17_1
this.levelHeightAccessor = genRegion.getLevelHeightAccessor();
#endif
this.blockEngine = new BlockLightEngine(genRegion);
this.skyEngine = new SkyLightEngine(genRegion);
}
@@ -148,35 +123,18 @@ public class WorldGenLevelLightEngine extends LevelLightEngine {
chunkAccess.setLightCorrect(false);
LevelChunkSection[] levelChunkSections = chunkAccess.getSections();
for (int i = 0; i <
#if POST_MC_1_17_1
chunkAccess.getSectionsCount()
#else
16
#endif
; ++i) {
for (int i = 0; i < chunkAccess.getSectionsCount(); ++i) {
LevelChunkSection levelChunkSection = levelChunkSections[i];
#if PRE_MC_1_17_1
if (!LevelChunkSection.isEmpty(levelChunkSection)) {
updateSectionStatus(SectionPos.of(chunkPos, i), false);
}
#elif PRE_MC_1_18_1
if (!LevelChunkSection.isEmpty(levelChunkSection)) {
int j = this.levelHeightAccessor.getSectionYFromSectionIndex(i);
updateSectionStatus(SectionPos.of(chunkPos, j), false);
}
#else
if (levelChunkSection.hasOnlyAir()) continue;
int j = this.levelHeightAccessor.getSectionYFromSectionIndex(i);
updateSectionStatus(SectionPos.of(chunkPos, j), false);
#endif
}
enableLightSources(chunkPos, true);
if (needLightBlockUpdate) {
chunkAccess.getLights().forEach(blockPos ->
onBlockEmissionIncrease(blockPos, chunkAccess.getLightEmission(blockPos)));
onBlockEmissionIncrease(blockPos, chunkAccess.getLightEmission(blockPos)));
}
chunkAccess.setLightCorrect(true);
}
@@ -203,8 +161,6 @@ public class WorldGenLevelLightEngine extends LevelLightEngine {
this.skyEngine.retainData(chunkPos, bl);
}
}
#if POST_MC_1_17_1
@Override
public int getLightSectionCount() {
throw new UnsupportedOperationException("This should never be used!");
@@ -217,5 +173,4 @@ public class WorldGenLevelLightEngine extends LevelLightEngine {
public int getMaxLightSection() {
throw new UnsupportedOperationException("This should never be used!");
}
#endif
}
@@ -1,22 +1,3 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration.mimicObject;
import java.util.Iterator;
@@ -25,8 +6,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.common.collect.ImmutableList;
@@ -37,38 +16,23 @@ import net.minecraft.core.SectionPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.StructureFeatureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.levelgen.WorldGenSettings;
#if PRE_MC_1_19
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.level.StructureFeatureManager;
#else
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.StructureManager;
#endif
#if POST_MC_1_18_1
import net.minecraft.world.level.levelgen.structure.StructureCheck;
#endif
import net.minecraft.world.level.levelgen.structure.StructureStart;
#if PRE_MC_1_19
public class WorldGenStructFeatManager extends StructureFeatureManager {
#else
public class WorldGenStructFeatManager extends StructureManager {
#endif
final WorldGenLevel genLevel;
WorldGenSettings worldGenSettings;
#if POST_MC_1_18_1
StructureCheck structureCheck;
#endif
public WorldGenStructFeatManager(WorldGenSettings worldGenSettings,
WorldGenLevel genLevel #if POST_MC_1_18_1 , StructureCheck structureCheck #endif ) {
super(genLevel, worldGenSettings #if POST_MC_1_18_1 , structureCheck #endif );
WorldGenLevel genLevel, StructureCheck structureCheck) {
super(genLevel, worldGenSettings, structureCheck);
this.genLevel = genLevel;
this.worldGenSettings = worldGenSettings;
}
@@ -77,7 +41,7 @@ public class WorldGenStructFeatManager extends StructureManager {
public WorldGenStructFeatManager forWorldGenRegion(WorldGenRegion worldGenRegion) {
if (worldGenRegion == genLevel)
return this;
return new WorldGenStructFeatManager(worldGenSettings, worldGenRegion #if POST_MC_1_18_1 , structureCheck #endif );
return new WorldGenStructFeatManager(worldGenSettings, worldGenRegion, structureCheck);
}
private ChunkAccess _getChunk(int x, int z, ChunkStatus status) {
@@ -85,32 +49,19 @@ public class WorldGenStructFeatManager extends StructureManager {
return genLevel.getChunk(x, z, status, false);
}
#if PRE_MC_1_18_1
@Override
public Stream<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos2,
StructureFeature<?> structureFeature) {
ChunkAccess chunk = _getChunk(sectionPos2.x(), sectionPos2.z(), ChunkStatus.STRUCTURE_REFERENCES);
if (chunk == null) return Stream.empty();
return chunk.getReferencesForFeature(structureFeature).stream().map(pos -> {
SectionPos sectPos = SectionPos.of(ChunkPos.getX(pos), 0, ChunkPos.getZ(pos));
ChunkAccess startChunk = _getChunk(sectPos.x(), sectPos.z(), ChunkStatus.STRUCTURE_STARTS);
if (startChunk == null) return null;
return this.getStartForFeature(sectPos, structureFeature, startChunk);
}).filter(structureStart -> structureStart != null && structureStart.isValid());
}
#else
@Override
public boolean hasAnyStructureAt(BlockPos blockPos) {
SectionPos sectionPos = SectionPos.of(blockPos);
public boolean hasAnyStructureAt(BlockPos blockPos) {
SectionPos sectionPos = SectionPos.of(blockPos);
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
if (chunk == null) return false;
return chunk.hasAnyStructureReferences();
}
return chunk.hasAnyStructureReferences();
}
#if MC_1_18_1
#if MC_VERSION_1_18_1
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
@SuppressWarnings({ "rawtypes", "unchecked" })
public List<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos,
StructureFeature<?> structureFeature) {
@@ -119,21 +70,21 @@ public class WorldGenStructFeatManager extends StructureManager {
// Copied from StructureFeatureManager::startsForFeature(...) with slight tweaks
LongSet longSet = chunk.getReferencesForFeature(structureFeature);
ImmutableList.Builder builder = ImmutableList.builder();
LongIterator longIterator = longSet.iterator();
while (longIterator.hasNext()) {
long l = (Long)longIterator.next();
SectionPos sectPos = SectionPos.of(new ChunkPos(l), genLevel.getMinSection());
ChunkAccess startChunk = _getChunk(sectPos.x(), sectPos.z(), ChunkStatus.STRUCTURE_STARTS);
if (startChunk == null) continue;
StructureStart<?> structureStart = this.getStartForFeature(sectPos, structureFeature, startChunk);
if (structureStart == null || !structureStart.isValid()) continue;
builder.add(structureStart);
}
return builder.build();
ImmutableList.Builder builder = ImmutableList.builder();
LongIterator longIterator = longSet.iterator();
while (longIterator.hasNext()) {
long l = (Long)longIterator.next();
SectionPos sectPos = SectionPos.of(new ChunkPos(l), genLevel.getMinSection());
ChunkAccess startChunk = _getChunk(sectPos.x(), sectPos.z(), ChunkStatus.STRUCTURE_STARTS);
if (startChunk == null) continue;
StructureStart<?> structureStart = this.getStartForFeature(sectPos, structureFeature, startChunk);
if (structureStart == null || !structureStart.isValid()) continue;
builder.add(structureStart);
}
return builder.build();
}
#else
#if PRE_MC_1_19
#elif MC_VERSION_1_18_2
@Override
public List<StructureStart> startsForFeature(SectionPos sectionPos, Predicate<ConfiguredStructureFeature<?, ?>> predicate) {
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
@@ -161,7 +112,7 @@ public class WorldGenStructFeatManager extends StructureManager {
@Override
public List<StructureStart> startsForFeature(SectionPos sectionPos, ConfiguredStructureFeature<?, ?> configuredStructureFeature) {
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
if (chunk == null) return (List<StructureStart>) Stream.empty();
if (chunk == null) return List.of();
// Copied from StructureFeatureManager::startsForFeature(...)
LongSet longSet = chunk.getReferencesForFeature(configuredStructureFeature);
@@ -175,55 +126,9 @@ public class WorldGenStructFeatManager extends StructureManager {
public Map<ConfiguredStructureFeature<?, ?>, LongSet> getAllStructuresAt(BlockPos blockPos) {
SectionPos sectionPos = SectionPos.of(blockPos);
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
if (chunk == null) return (Map<ConfiguredStructureFeature<?, ?>, LongSet>) Stream.empty();
return chunk.getAllReferences();
}
#else
@Override
public List<StructureStart> startsForStructure(ChunkPos sectionPos, Predicate<Structure> predicate) {
ChunkAccess chunk = _getChunk(sectionPos.x, sectionPos.z, ChunkStatus.STRUCTURE_REFERENCES);
if (chunk == null) return List.of();
// Copied from StructureFeatureManager::startsForFeature(...)
Map<Structure, LongSet> map = chunk.getAllReferences();
ImmutableList.Builder<StructureStart> builder = ImmutableList.builder();
Iterator<Map.Entry<Structure, LongSet>> var5 = map.entrySet().iterator();
while (var5.hasNext()) {
Map.Entry<Structure, LongSet> entry = var5.next();
Structure configuredStructureFeature = entry.getKey();
if (predicate.test(configuredStructureFeature)) {
LongSet var10002 = (LongSet) entry.getValue();
Objects.requireNonNull(builder);
this.fillStartsForStructure(configuredStructureFeature, var10002, builder::add);
}
}
return builder.build();
}
@Override
public List<StructureStart> startsForStructure(SectionPos sectionPos, Structure structure) {
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
if (chunk == null) return (List<StructureStart>) Stream.empty();
// Copied from StructureFeatureManager::startsForFeature(...)
LongSet longSet = chunk.getReferencesForStructure(structure);
ImmutableList.Builder<StructureStart> builder = ImmutableList.builder();
Objects.requireNonNull(builder);
this.fillStartsForStructure(structure, longSet, builder::add);
return builder.build();
}
@Override
public Map<Structure, LongSet> getAllStructuresAt(BlockPos blockPos) {
SectionPos sectionPos = SectionPos.of(blockPos);
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
if (chunk == null) return (Map<Structure, LongSet>) Stream.empty();
if (chunk == null) return Map.of();
return chunk.getAllReferences();
}
#endif
#endif
#endif
}
}
@@ -1,22 +1,3 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration.step;
import java.util.ArrayList;
@@ -27,9 +8,7 @@ import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
import net.minecraft.core.Registry;
import net.minecraft.server.level.WorldGenRegion;
#if PRE_MC_1_19
import net.minecraft.world.level.StructureFeatureManager;
#endif
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
@@ -38,9 +17,7 @@ import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.levelgen.DebugLevelSource;
import net.minecraft.world.level.levelgen.FlatLevelSource;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
#if POST_MC_1_18_1
import net.minecraft.world.level.levelgen.blending.Blender;
#endif
public final class StepBiomes {
/**
@@ -71,15 +48,8 @@ public final class StepBiomes {
for (ChunkAccess chunk : chunksToDo) {
// System.out.println("StepBiomes: "+chunk.getPos());
#if PRE_MC_1_18_1
environment.params.generator.createBiomes(environment.params.biomes, chunk);
#elif PRE_MC_1_19
chunk = environment.joinSync(environment.params.generator.createBiomes(environment.params.biomes, Runnable::run, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#else
chunk = environment.joinSync(environment.params.generator.createBiomes(environment.params.biomes, Runnable::run, environment.params.randomState, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#endif
}
}
}
@@ -1,29 +1,9 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration.step;
import java.util.ArrayList;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.LightedWorldGenRegion;
import com.seibel.lod.core.util.gridList.ArrayGridList;
import net.minecraft.ReportedException;
@@ -31,10 +11,7 @@ import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.levelgen.Heightmap;
#if POST_MC_1_18_1
import net.minecraft.world.level.levelgen.blending.Blender;
#endif
public final class StepFeatures {
/**
@@ -52,7 +29,7 @@ public final class StepFeatures {
public final ChunkStatus STATUS = ChunkStatus.FEATURES;
public void generateGroup(ThreadedParameters tParams, LightedWorldGenRegion worldGenRegion,
public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion,
ArrayGridList<ChunkAccess> chunks) {
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
@@ -64,20 +41,20 @@ public final class StepFeatures {
for (ChunkAccess chunk : chunksToDo) {
try {
#if PRE_MC_1_18_1
worldGenRegion.setOverrideCenter(chunk.getPos());
Heightmap.primeHeightmaps(chunk, STATUS.heightmapsAfter());
environment.params.generator.applyBiomeDecoration(worldGenRegion, tParams.structFeat);
#else
Heightmap.primeHeightmaps(chunk, STATUS.heightmapsAfter());
environment.params.generator.applyBiomeDecoration(worldGenRegion, chunk,
tParams.structFeat.forWorldGenRegion(worldGenRegion));
#endif
Blender.generateBorderTicks(worldGenRegion, chunk);
} catch (ReportedException e) {
e.printStackTrace();
// FIXME: Features concurrent modification issue. Something about cocobeans might just
// error out. For now just retry.
// FIXME: Features concurrent modification issue. Something about cocobeans just
// aren't happy
// For now just retry.
}
}
}/*
for (ChunkAccess chunk : chunks) {
Heightmap.primeHeightmaps(chunk,
EnumSet.of(Heightmap.Types.MOTION_BLOCKING, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
Heightmap.Types.OCEAN_FLOOR, Heightmap.Types.WORLD_SURFACE));
}*/
}
}
@@ -1,22 +1,3 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration.step;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
@@ -28,7 +9,6 @@ import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.lighting.LightEventListener;
public final class StepLight {
@@ -47,10 +27,9 @@ public final class StepLight {
public final ChunkStatus STATUS = ChunkStatus.LIGHT;
public void generateGroup(
#if PRE_MC_1_17_1 LevelLightEngine lightEngine,
#else LightEventListener lightEngine, #endif
public void generateGroup(LightEventListener lightEngine,
ArrayGridList<ChunkAccess> chunks) {
//ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
for (ChunkAccess chunk : chunks) {
if (chunk.getStatus().isOrAfter(STATUS)) continue;
@@ -73,9 +52,7 @@ public final class StepLight {
} catch (Exception e) {
e.printStackTrace();
}
#if POST_MC_1_18_1
if (chunk instanceof LevelChunk) ((LevelChunk)chunk).setClientLightReady(true);
#endif
chunk.setLightCorrect(true);
}
lightEngine.runUpdates(Integer.MAX_VALUE, true, true);
@@ -1,42 +1,25 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration.step;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import com.google.common.collect.Sets;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
import com.seibel.lod.core.util.objects.UncheckedInterruptedException;
import net.minecraft.server.level.WorldGenRegion;
#if POST_MC_1_17_1
#endif
#if PRE_MC_1_19
#endif
import net.minecraft.util.Mth;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.StructureFeatureManager;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.ProtoChunk;
#if POST_MC_1_18_1
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseSettings;
import net.minecraft.world.level.levelgen.blending.Blender;
#endif
public final class StepNoise {
/**
@@ -67,19 +50,8 @@ public final class StepNoise {
for (ChunkAccess chunk : chunksToDo) {
// System.out.println("StepNoise: "+chunk.getPos());
#if PRE_MC_1_17_1
environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk);
#elif PRE_MC_1_18_1
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run,
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#elif PRE_MC_1_19
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#else
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), environment.params.randomState,
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#endif
UncheckedInterruptedException.throwIfInterrupted();
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
}
}
}
@@ -1,22 +1,3 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration.step;
import java.util.ArrayList;
@@ -32,9 +13,7 @@ import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.ChunkPos;
#if PRE_MC_1_19
import net.minecraft.world.level.StructureFeatureManager;
#endif
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk;
@@ -1,22 +1,3 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration.step;
import java.util.ArrayList;
@@ -67,31 +48,19 @@ public final class StepStructureStart {
chunksToDo.add(chunk);
}
#if PRE_MC_1_19
if (environment.params.worldGenSettings.generateFeatures()) {
#elif POST_MC_1_19
if (environment.params.worldGenSettings.generateStructures()) {
#endif
for (ChunkAccess chunk : chunksToDo) {
// System.out.println("StepStructureStart: "+chunk.getPos());
#if PRE_MC_1_19
environment.params.generator.createStructures(environment.params.registry, tParams.structFeat, chunk, environment.params.structures,
environment.params.worldSeed);
#elif POST_MC_1_19
environment.params.generator.createStructures(environment.params.registry, environment.params.randomState, tParams.structFeat, chunk, environment.params.structures,
environment.params.worldSeed);
#endif
#if POST_MC_1_18_1
try {
tParams.structCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts());
} catch (ArrayIndexOutOfBoundsException e) {
// There's a rare issue with StructStart where it throws ArrayIndexOutOfBounds
// This means the structFeat is corrupted (For some reason) and I need to reset it.
// TODO: Figure out in the future why this happens even though I am using new structFeat - OLD
// TODO: Is this still a problem?
// TODO: Figure out in the future why this happens even though I am using new structFeat
throw new StepStructureStart.StructStartCorruptedException(e);
}
#endif
}
}
}
@@ -1,22 +1,3 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.common.wrappers.worldGeneration.step;
import java.util.ArrayList;
@@ -58,13 +39,8 @@ public final class StepSurface {
for (ChunkAccess chunk : chunksToDo) {
// System.out.println("StepSurface: "+chunk.getPos());
#if PRE_MC_1_18_1
environment.params.generator.buildSurfaceAndBedrock(worldGenRegion, chunk);
#elif PRE_MC_1_19
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk);
#else
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), environment.params.randomState, chunk);
#endif
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion),
chunk);
}
}
}
@@ -1,45 +0,0 @@
accessWidener v1 named
# used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
# used when rendering
accessible field com/mojang/blaze3d/vertex/VertexBuffer vertexCount I
accessible field com/mojang/blaze3d/vertex/VertexBuffer id I
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
# pre-render setup
accessible field net/minecraft/client/renderer/LevelRenderer renderChunks Lit/unimi/dsi/fastutil/objects/ObjectList;
accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo
accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chunk Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;
# used for grabbing vanilla rendered chunks
accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo
accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chunk Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;
#accessible field net/minecraft/world/entity/Entity blockPosition Lnet/minecraft/core/BlockPos;
# lighting
accessible field net/minecraft/client/renderer/LightTexture lightPixels Lcom/mojang/blaze3d/platform/NativeImage;
accessible field net/minecraft/client/renderer/LightTexture lightTexture Lnet/minecraft/client/renderer/texture/DynamicTexture;
accessible field net/minecraft/world/level/lighting/LevelLightEngine blockEngine Lnet/minecraft/world/level/lighting/LayerLightEngine;
accessible field net/minecraft/world/level/lighting/LevelLightEngine skyEngine Lnet/minecraft/world/level/lighting/LayerLightEngine;
# world generation
accessible method net/minecraft/world/level/levelgen/Heightmap setHeight (III)V
accessible field net/minecraft/world/level/biome/Biome generationSettings Lnet/minecraft/world/level/biome/BiomeGenerationSettings;
accessible field net/minecraft/world/level/biome/Biome biomeCategory Lnet/minecraft/world/level/biome/Biome$BiomeCategory;
#accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Lnet/minecraft/core/Holder;
#accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doCreateBiomes (Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;)V
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
# lod generation from save file
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
accessible method net/minecraft/server/level/ChunkMap readChunk (Lnet/minecraft/world/level/ChunkPos;)Lnet/minecraft/nbt/CompoundTag;
# grabbing textures
accessible field net/minecraft/client/renderer/block/model/BakedQuad sprite Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite framesX [I
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite framesY [I
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite mainImage [Lcom/mojang/blaze3d/platform/NativeImage;
extendable class com/mojang/math/Matrix4f
@@ -1,48 +0,0 @@
accessWidener v1 named
# used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
# used when rendering
accessible field com/mojang/blaze3d/vertex/VertexBuffer indexCount I
accessible field com/mojang/blaze3d/vertex/VertexBuffer vertextBufferId I
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
# pre-render setup
accessible field net/minecraft/client/renderer/LevelRenderer renderChunks Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo
accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chunk Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;
# used for grabbing vanilla rendered chunks
accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo
accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chunk Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;
# lighting
accessible field net/minecraft/client/renderer/LightTexture lightPixels Lcom/mojang/blaze3d/platform/NativeImage;
accessible field net/minecraft/client/renderer/LightTexture lightTexture Lnet/minecraft/client/renderer/texture/DynamicTexture;
accessible field net/minecraft/world/level/lighting/LevelLightEngine blockEngine Lnet/minecraft/world/level/lighting/LayerLightEngine;
accessible field net/minecraft/world/level/lighting/LevelLightEngine skyEngine Lnet/minecraft/world/level/lighting/LayerLightEngine;
# world generation
accessible method net/minecraft/world/level/levelgen/Heightmap setHeight (III)V
accessible field net/minecraft/world/level/biome/Biome generationSettings Lnet/minecraft/world/level/biome/BiomeGenerationSettings;
accessible field net/minecraft/world/level/biome/Biome biomeCategory Lnet/minecraft/world/level/biome/Biome$BiomeCategory;
# accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Lnet/minecraft/core/Holder;
#accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doCreateBiomes (Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;)V
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
# lod generation from save file
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
accessible method net/minecraft/server/level/ChunkMap readChunk (Lnet/minecraft/world/level/ChunkPos;)Lnet/minecraft/nbt/CompoundTag;
# grabbing textures
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite animatedTexture Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture;
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite width I
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite height I
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite mainImage [Lcom/mojang/blaze3d/platform/NativeImage;
accessible class net/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture
accessible method net/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture getFrameX (I)I
accessible method net/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture getFrameY (I)I
extendable class com/mojang/math/Matrix4f
@@ -1,47 +0,0 @@
accessWidener v1 named
# used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
# used when rendering
accessible field com/mojang/blaze3d/vertex/VertexBuffer indexCount I
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
# used for grabbing vanilla rendered chunks
accessible field net/minecraft/client/renderer/LevelRenderer renderChunkStorage Ljava/util/concurrent/atomic/AtomicReference;
accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkStorage
accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo
accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chunk Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;
# lighting
accessible field net/minecraft/client/renderer/LightTexture lightPixels Lcom/mojang/blaze3d/platform/NativeImage;
accessible field net/minecraft/client/renderer/LightTexture lightTexture Lnet/minecraft/client/renderer/texture/DynamicTexture;
accessible field net/minecraft/world/level/lighting/LevelLightEngine blockEngine Lnet/minecraft/world/level/lighting/LayerLightEngine;
accessible field net/minecraft/world/level/lighting/LevelLightEngine skyEngine Lnet/minecraft/world/level/lighting/LayerLightEngine;
# world generation
accessible method net/minecraft/world/level/levelgen/Heightmap setHeight (III)V
accessible field net/minecraft/world/level/biome/Biome generationSettings Lnet/minecraft/world/level/biome/BiomeGenerationSettings;
# accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Lnet/minecraft/core/Holder;
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
accessible method net/minecraft/server/level/ChunkMap readChunk (Lnet/minecraft/world/level/ChunkPos;)Ljava/util/concurrent/CompletableFuture;
# lod generation from save file
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
# grabbing textures
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite animatedTexture Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture;
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite width I
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite height I
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite mainImage [Lcom/mojang/blaze3d/platform/NativeImage;
accessible class net/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture
accessible method net/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture getFrameX (I)I
accessible method net/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture getFrameY (I)I
extendable class com/mojang/math/Matrix4f
# hacky stuff
accessible field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
mutable field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
@@ -1,3 +0,0 @@
{
"accessWidener": "lod.accesswidener"
}
@@ -1,6 +1,5 @@
accessWidener v1 named
# used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
Submodule
+1
Submodule core added at 02b0637adc
Submodule coreSubProjects deleted from c3c170d07a
+64 -57
View File
@@ -1,27 +1,33 @@
version = rootProject.versionStr
plugins {
id "com.github.johnrengelman.shadow" version "7.1.0"
}
version = rootProject.mod_version+"-"+rootProject.minecraft_version+"-"+new Date().format("yyyy_MM_dd_HH_mm")
loom {
accessWidenerPath.set(project(":common").file("src/main/resources/lod.accesswidener"))
}
architectury {
platformSetupLoomIde()
fabric()
}
loom {
accessWidenerPath = project(":common").loom.accessWidenerPath
}
configurations {
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
developmentFabric.extendsFrom common
// The addModJar basically embeds the mod to the built jar
addModJar
include.extendsFrom addModJar
modImplementation.extendsFrom addModJar
}
repositories {
// Required for ModMenu
maven { url "https://maven.terraformersmc.com/" }
}
def addMod(path, enabled) {
if (enabled == "2")
dependencies { modImplementation(path) }
@@ -33,19 +39,10 @@ dependencies {
// Fabric loader
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
// Architectury API
if (minecraft_version == "1.16.5") {
addModJar("me.shedaniel:architectury-fabric:${rootProject.architectury_version}")
} else {
addModJar("dev.architectury:architectury-fabric:${rootProject.architectury_version}")
}
// Fabric API
addModJar(fabricApi.module("fabric-lifecycle-events-v1", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-key-binding-api-v1", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-rendering-v1", rootProject.fabric_api_version)) // TODO: Remove this as it is only needed in 1 line (FabricClientProxy)
addModJar(fabricApi.module("fabric-api-base", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-networking-api-v1", rootProject.fabric_api_version))
// Mod Menu
modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}")
@@ -57,13 +54,11 @@ dependencies {
addMod("curse.maven:phosphor-372124:${rootProject.phosphor_version_fabric}", rootProject.enable_phosphor)
// Sodium
addMod("maven.modrinth:sodium:${rootProject.sodium_version}", rootProject.enable_sodium)
// if (rootProject.enable_sodium != "0") {
// implementation "org.joml:joml:1.10.2"
// modImplementation(fabricApi.module("fabric-rendering-data-attachment-v1", rootProject.fabric_api_version))
// modImplementation(fabricApi.module("fabric-rendering-fluids-v1", rootProject.fabric_api_version))
// }
addMod("curse.maven:sodium-394468:${rootProject.sodium_version}", rootProject.enable_sodium)
implementation "org.joml:joml:1.10.2"
modImplementation(fabricApi.module("fabric-rendering-data-attachment-v1", rootProject.fabric_api_version))
modImplementation(fabricApi.module("fabric-rendering-fluids-v1", rootProject.fabric_api_version))
// Lithium
addMod("maven.modrinth:lithium:${rootProject.lithium_version}", rootProject.enable_lithium)
@@ -73,9 +68,6 @@ dependencies {
// BCLib
addMod("com.github.paulevsGitch:BCLib:${rootProject.bclib_version}", rootProject.enable_bclib)
// Canvas
addMod("io.vram:canvas-fabric-${project.canvas_version}", rootProject.enable_canvas)
// Immersive Portals
/*
modImplementation("com.github.qouteall.ImmersivePortalsMod:build:${rootProject.immersive_portals_version}") {
@@ -90,56 +82,71 @@ dependencies {
exclude(group: "net.fabricmc.fabric-api")
transitive(false)
}
*/
*/
// Toml
shadowMe("com.electronwill.night-config:toml:${rootProject.toml_version}") {}
common(project(path: ":common", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive false }
}
shadowJar {
exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon, project.configurations.shadowMe, project.configurations.customModule]
shadowMe(project(path: ":common", configuration: "transformProductionFabric")) { transitive false }
// Compression
relocate 'org.tukaani', 'distanthorizons.libraries.tukaani'
relocate 'org.apache.commons.compress', 'distanthorizons.libraries.apache.commons.compress'
// NightConfig (includes Toml & Json)
relocate 'com.electronwill.nightconfig', 'distanthorizons.libraries.electronwill.nightconfig'
// Theming
relocate 'com.formdev.flatlaf', 'distanthorizons.libraries.formdev.flatlaf'
// SVG
relocate 'com.kitfox.svg', 'distanthorizons.libraries.kitfox.svg'
classifier "dev-shadow"
mergeServiceFiles()
common 'org.tukaani:xz:1.9'
common 'org.apache.commons:commons-compress:1.21'
shadowMe 'org.tukaani:xz:1.9'
shadowMe 'org.apache.commons:commons-compress:1.21'
}
remapJar {
injectAccessWidener = true
input.set shadowJar.archiveFile
dependsOn shadowJar
classifier null
// This method copies the access wideners from the common project to the fabric project. And it was generated by Github Copilot
task copyAccessWidener(type: Copy) {
from project(":common").file("src/main/resources/lod.accesswidener")
into file("src/generated/resources")
}
task copyCoreResources(type: Copy) {
from fileTree(project(":core").file("src/main/resources"))
into file("build/resources/main")
}
task deleteResources(type: Delete) {
delete file("build/resources/main")
}
processResources {
dependsOn(copyCoreResources)
task copyCommonResources(type: Copy) {
from fileTree(project(":common").file("src/main/resources"))
into file("build/resources/main")
}
runClient {
dependsOn(copyCoreResources)
dependsOn(copyCommonResources)
jvmArgs "-XX:-OmitStackTraceInFastThrow"
finalizedBy(deleteResources)
}
processResources {
dependsOn(copyAccessWidener)
}
shadowJar {
configurations = [project.configurations.shadowMe]
relocate 'org.tukaani', 'shaded.tukaani'
relocate 'org.apache.commons.compress', 'shaded.apache.commons.compress'
relocate 'com.electronwill.nightconfig', 'shaded.electronwill.nightconfig'
relocate 'com.seibel.lod.common', 'fabric.com.seibel.lod.common'
classifier "dev-shadow"
}
remapJar {
input.set shadowJar.archiveFile
dependsOn shadowJar
classifier null
}
jar {
classifier "dev"
}
@@ -1,29 +0,0 @@
package com.seibel.lod;
import com.seibel.lod.common.wrappers.DependencySetup;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
@Environment(EnvType.CLIENT)
public class FabricClientMain implements ClientModInitializer {
public static FabricClientProxy client_proxy;
public static FabricServerProxy server_proxy;
// Do if implements ClientModInitializer
// This loads the mod before minecraft loads which causes a lot of issues
@Override
public void onInitializeClient() {
DependencySetup.createClientBindings();
FabricMain.init();
server_proxy = new FabricServerProxy(false);
server_proxy.registerEvents();
client_proxy = new FabricClientProxy();
client_proxy.registerEvents();
ClientLifecycleEvents.CLIENT_STARTED.register((mc) -> FabricMain.postInit());
}
}
@@ -1,174 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod;
import com.seibel.lod.common.wrappers.McObjectConverter;
import com.seibel.lod.common.wrappers.world.ClientLevelWrapper;
import com.seibel.lod.core.api.internal.ClientApi;
import com.seibel.lod.core.config.Config;
import com.mojang.blaze3d.platform.InputConstants;
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
import com.seibel.lod.core.dependencyInjection.ModAccessorInjector;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import com.seibel.lod.wrappers.modAccessor.SodiumAccessor;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen;
import java.util.HashSet;
import org.apache.logging.log4j.Logger;
import org.lwjgl.glfw.GLFW;
/**
* This handles all events sent to the client,
* and is the starting point for most of the mod.
*
* @author coolGi
* @author Ran
* @version 11-23-2021
*/
@Environment(EnvType.CLIENT)
public class FabricClientProxy
{
private final ClientApi clientApi = ClientApi.INSTANCE;
private static final Logger LOGGER = DhLoggerBuilder.getLogger("FabricClientProxy");
/**
* Registers Fabric Events
* @author Ran
*/
public void registerEvents() {
LOGGER.info("Registering Fabric Client Events");
/* Register the mod needed event callbacks */
// ClientTickEvent
ClientTickEvents.START_CLIENT_TICK.register((client) -> {
//LOGGER.info("ClientTickEvent.START_CLIENT_TICK");
ClientApi.INSTANCE.clientTickEvent();
});
// ClientLevelLoadEvent - Done in MixinClientPacketListener
// ClientLevelUnloadEvent - Done in MixinClientPacketListener
// ClientChunkLoadEvent
// TODO: Is using setClientLightReady one still better?
//#if PRE_MC_1_18_1 // in 1.18+, we use mixin hook in setClientLightReady(true)
ClientChunkEvents.CHUNK_LOAD.register((level, chunk) ->
{
ClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level);
ClientApi.INSTANCE.clientChunkLoadEvent(
new ChunkWrapper(chunk, level, wrappedLevel),
wrappedLevel
);
});
//#endif
// ClientChunkSaveEvent
ClientChunkEvents.CHUNK_UNLOAD.register((level, chunk) ->
{
ClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level);
ClientApi.INSTANCE.clientChunkSaveEvent(
new ChunkWrapper(chunk, level, wrappedLevel),
wrappedLevel
);
});
// RendererStartupEvent - Done in MixinGameRenderer
// RendererShutdownEvent - Done in MixinGameRenderer
SodiumAccessor sodiumAccessor = (SodiumAccessor) ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class);
// ClientRenderLevelTerrainEvent
WorldRenderEvents.AFTER_SETUP.register((renderContext) -> {
if (sodiumAccessor != null) {
sodiumAccessor.levelWrapper = ClientLevelWrapper.getWrapper(renderContext.world());
sodiumAccessor.mcModelViewMatrix = McObjectConverter.Convert(renderContext.matrixStack().last().pose());
sodiumAccessor.mcProjectionMatrix = McObjectConverter.Convert(renderContext.projectionMatrix());
sodiumAccessor.partialTicks = renderContext.tickDelta();
} else {
clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()),
McObjectConverter.Convert(renderContext.matrixStack().last().pose()),
McObjectConverter.Convert(renderContext.projectionMatrix()),
renderContext.tickDelta());
}
}
);
// Debug keyboard event
// FIXME: Use better hooks so it doesn't trigger even in text boxes
ClientTickEvents.END_CLIENT_TICK.register(client -> {
if (client.player != null && isValidTime()) onKeyInput();
});
}
private boolean isValidTime() {
return !(Minecraft.getInstance().screen instanceof TitleScreen);
}
// public void blockChangeEvent(LevelAccessor world, BlockPos pos) {
// if (!isValidTime()) return;
// IChunkWrapper chunk = new ChunkWrapper(world.getChunk(pos), world);
// DimensionTypeWrapper dimType = DimensionTypeWrapper.getDimensionTypeWrapper(world.dimensionType());
//
// // recreate the LOD where the blocks were changed
// // TODO: serverApi.blockChangeEvent(chunk, dimType);
// }
private static final int[] KEY_TO_CHECK_FOR = {GLFW.GLFW_KEY_F6, GLFW.GLFW_KEY_F8};
HashSet<Integer> previousKeyDown = new HashSet<>();
public void onKeyInput() {
if (Config.Client.Advanced.Debugging.enableDebugKeybindings.get())
{
HashSet<Integer> currentKeyDown = new HashSet<Integer>();
// Note: Minecraft's InputConstants is same as GLFW Key values
//TODO: Use mixin to hook directly into the GLFW Keyboard event in minecraft KeyboardHandler
// Check all keys we need
for (int i = GLFW.GLFW_KEY_A; i <= GLFW.GLFW_KEY_Z; i++) {
if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), i)) {
currentKeyDown.add(i);
}
}
for (int i : KEY_TO_CHECK_FOR) {
if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), i)) {
currentKeyDown.add(i);
}
}
// Diff and trigger events
for (int c : currentKeyDown) {
if (!previousKeyDown.contains(c)) {
ClientApi.INSTANCE.keyPressedEvent(c);
}
}
// Update the set
previousKeyDown = currentKeyDown;
}
}
}
@@ -1,39 +0,0 @@
package com.seibel.lod;
import com.seibel.lod.common.wrappers.DependencySetup;
import com.seibel.lod.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
import com.seibel.lod.core.util.LodUtil;
import net.fabricmc.api.DedicatedServerModInitializer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.minecraft.server.dedicated.DedicatedServer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@Environment(EnvType.SERVER)
public class FabricDedicatedServerMain implements DedicatedServerModInitializer
{
private static final Logger LOGGER = LogManager.getLogger(FabricDedicatedServerMain.class.getSimpleName());
public static FabricServerProxy server_proxy;
public boolean hasPostSetupDone = false;
@Override
public void onInitializeServer() {
DependencySetup.createServerBindings();
FabricMain.init();
server_proxy = new FabricServerProxy(true);
server_proxy.registerEvents();
ServerLifecycleEvents.SERVER_STARTING.register((server) -> {
if (hasPostSetupDone) return;
hasPostSetupDone = true;
LodUtil.assertTrue(server instanceof DedicatedServer);
MinecraftDedicatedServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer) server;
FabricMain.postInit();
LOGGER.info("Dedicated server inited at {}", server.getServerDirectory());
});
}
}
@@ -1,94 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod;
import com.seibel.lod.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
import com.seibel.lod.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
import com.seibel.lod.common.LodCommonMain;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.DependencyInjection.ApiEventInjector;
import com.seibel.lod.core.dependencyInjection.ModAccessorInjector;
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.*;
import com.seibel.lod.wrappers.modAccessor.BCLibAccessor;
import com.seibel.lod.wrappers.modAccessor.OptifineAccessor;
import com.seibel.lod.wrappers.modAccessor.SodiumAccessor;
import com.seibel.lod.wrappers.modAccessor.StarlightAccessor;
import com.seibel.lod.wrappers.FabricDependencySetup;
import org.apache.logging.log4j.Logger;
/**
* Initialize and setup the Mod. <br>
* If you are looking for the real start of the mod
* check out the ClientProxy.
*
* @author coolGi
* @author Ran
* @version 9-2-2022
*/
public class FabricMain
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public static void postInit() {
LOGGER.info("Post-Initializing Mod");
FabricDependencySetup.runDelayedSetup();
if (Config.Client.Graphics.FogQuality.disableVanillaFog.get() && SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("bclib"))
ModAccessorInjector.INSTANCE.get(IBCLibAccessor.class).setRenderCustomFog(false); // Remove BCLib's fog
LOGGER.info("Mod Post-Initialized");
}
// This loads the mod after minecraft loads which doesn't causes a lot of issues
public static void init()
{
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
LOGGER.info("Initializing Mod");
LodCommonMain.startup(null);
FabricDependencySetup.createInitialBindings();
LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
if (SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("sodium")) {
ModAccessorInjector.INSTANCE.bind(ISodiumAccessor.class, new SodiumAccessor());
}
if (SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("starlight")) {
ModAccessorInjector.INSTANCE.bind(IStarlightAccessor.class, new StarlightAccessor());
}
if (SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("optifine")) {
ModAccessorInjector.INSTANCE.bind(IOptifineAccessor.class, new OptifineAccessor());
}
if (SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("bclib")) {
ModAccessorInjector.INSTANCE.bind(IBCLibAccessor.class, new BCLibAccessor());
}
LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
// Init config
// The reason im initialising in this rather than the post init process is cus im using this for the auto updater
LodCommonMain.initConfig();
}
}
@@ -1,115 +0,0 @@
package com.seibel.lod;
import com.seibel.lod.common.networking.Networking;
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
import com.seibel.lod.common.wrappers.world.ClientLevelWrapper;
import com.seibel.lod.common.wrappers.world.ServerLevelWrapper;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.lod.core.api.internal.ServerApi;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import org.apache.logging.log4j.Logger;
import java.util.function.Supplier;
/**
* This handles all events sent to the server,
* and is the starting point for most of the mod.
*
* @author Ran
* @author Tomlee
* @version 5-11-2022
*/
public class FabricServerProxy {
private final ServerApi serverApi = ServerApi.INSTANCE;
private static final Logger LOGGER = DhLoggerBuilder.getLogger("FabricServerProxy");
private final boolean isDedicated;
public static Supplier<Boolean> isGenerationThreadChecker = null;
public FabricServerProxy(boolean isDedicated) {
this.isDedicated = isDedicated;
}
private boolean isValidTime() {
if (isDedicated) return true;
//FIXME: This may cause init issue...
return !(Minecraft.getInstance().screen instanceof TitleScreen);
}
private ClientLevelWrapper getLevelWrapper(ClientLevel level) {
return ClientLevelWrapper.getWrapper(level);
}
private ServerLevelWrapper getLevelWrapper(ServerLevel level) {
return ServerLevelWrapper.getWrapper(level);
}
/**
* Registers Fabric Events
* @author Ran, Tomlee
*/
public void registerEvents() {
LOGGER.info("Registering Fabric Server Events");
isGenerationThreadChecker = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread;
/* Register the mod needed event callbacks */
// TEST EVENT
//ServerTickEvents.END_SERVER_TICK.register(this::tester);
// ServerTickEvent
ServerTickEvents.END_SERVER_TICK.register((server) -> serverApi.serverTickEvent());
// ServerWorldLoadEvent
//TODO: Check if both of this use the correct timed events. (i.e. is it 'ed' or 'ing' one?)
ServerLifecycleEvents.SERVER_STARTING.register((server) -> {
if (isValidTime()) ServerApi.INSTANCE.serverWorldLoadEvent(isDedicated);
});
// ServerWorldUnloadEvent
ServerLifecycleEvents.SERVER_STOPPED.register((server) -> {
if (isValidTime()) ServerApi.INSTANCE.serverWorldUnloadEvent();
});
// ServerLevelLoadEvent
ServerWorldEvents.LOAD.register((server, level)
-> {
if (isValidTime()) ServerApi.INSTANCE.serverLevelLoadEvent(getLevelWrapper(level));
});
// ServerLevelUnloadEvent
ServerWorldEvents.UNLOAD.register((server, level)
-> {
if (isValidTime()) ServerApi.INSTANCE.serverLevelUnloadEvent(getLevelWrapper(level));
});
// ServerChunkLoadEvent
ServerChunkEvents.CHUNK_LOAD.register((server, chunk)
-> {
ILevelWrapper level = getLevelWrapper((ServerLevel) chunk.getLevel());
if (isValidTime()) ServerApi.INSTANCE.serverChunkLoadEvent(
new ChunkWrapper(chunk, chunk.getLevel(), level),
level);
}
);
// ServerChunkSaveEvent - Done in MixinChunkMap
}
// This just exists here for testing purposes, it'll be removed in the future
public void tester(MinecraftServer server) {
for (ServerPlayer player : server.getPlayerList().getPlayers()) {
FriendlyByteBuf payload = Networking.createNew();
payload.writeInt(1);
System.out.println("Sending int 1");
Networking.send(player, payload);
}
}
}
@@ -0,0 +1,194 @@
/*
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.fabric;
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.api.EventApi;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.mojang.blaze3d.platform.InputConstants;
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
import com.seibel.lod.common.wrappers.world.DimensionTypeWrapper;
import com.seibel.lod.common.wrappers.world.WorldWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.fabric.mixins.MixinUtilBackgroudThread;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.chunk.LevelChunk;
import java.util.HashSet;
import java.util.List;
import java.util.function.Supplier;
import org.lwjgl.glfw.GLFW;
/**
* This handles all events sent to the client,
* and is the starting point for most of the mod.
*
* @author coolGi2007
* @author Ran
* @version 11-23-2021
*/
public class ClientProxy
{
private final EventApi eventApi = EventApi.INSTANCE;
private final ClientApi clientApi = ClientApi.INSTANCE;
public static Supplier<Boolean> isGenerationThreadChecker = null;
/**
* Registers Fabric Events
* @author Ran
*/
public void registerEvents() {
/* Registor the mod accessor*/
/* World Events */
//ServerTickEvents.START_SERVER_TICK.register(this::serverTickEvent);
ServerTickEvents.END_SERVER_TICK.register(this::serverTickEvent);
/* World Events */
//ServerChunkEvents.CHUNK_LOAD.register(this::chunkLoadEvent);
//ClientChunkEvents.CHUNK_LOAD.register(this::chunkLoadEvent);
/* World Events */
ServerWorldEvents.LOAD.register((server, level) -> this.worldLoadEvent(level));
ServerWorldEvents.UNLOAD.register((server, level) -> this.worldUnloadEvent(level));
/* The Client World Events are in the mixins
Client world load event is in MixinClientLevel
Client world unload event is in MixinMinecraft */
/* The save events are in MixinServerLevel */
/* Keyboard Events */
ClientTickEvents.END_CLIENT_TICK.register(client -> {
if (client.player != null) onKeyInput();
});
isGenerationThreadChecker = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread;
}
public void serverTickEvent(MinecraftServer server)
{
eventApi.serverTickEvent();
}
public void chunkLoadEvent(LevelAccessor level, LevelChunk chunk)
{
clientApi.clientChunkLoadEvent(new ChunkWrapper(chunk, level),
WorldWrapper.getWorldWrapper(level));
}
public void worldSaveEvent()
{
eventApi.worldSaveEvent();
}
/** This is also called when a new dimension loads */
public void worldLoadEvent(Level level)
{
if (level != null) {
eventApi.worldLoadEvent(WorldWrapper.getWorldWrapper(level));
}
}
public void worldUnloadEvent(Level level)
{
if (level != null) {
eventApi.worldUnloadEvent(WorldWrapper.getWorldWrapper(level));
}
}
/**
* Can someone tell me how to make this better
* @author Ran
*
* public void blockChangeEvent(BlockEventData event) {
* // we only care about certain block events
* if (event.getClass() == BlockEventData.BreakEvent.class ||
* event.getClass() == BlockEventData.EntityPlaceEvent.class ||
* event.getClass() == BlockEventData.EntityMultiPlaceEvent.class ||
* event.getClass() == BlockEventData.FluidPlaceBlockEvent.class ||
* event.getClass() == BlockEventData.PortalSpawnEvent.class)
* {
* IChunkWrapper chunk = new ChunkWrapper(event.getWorld().getChunk(event.getPos()));
* DimensionTypeWrapper dimType = DimensionTypeWrapper.getDimensionTypeWrapper(event.getWorld().dimensionType());
*
* // recreate the LOD where the blocks were changed
* eventApi.blockChangeEvent(chunk, dimType);
* }
* }
*/
public void blockChangeEvent(LevelAccessor world, BlockPos pos) {
IChunkWrapper chunk = new ChunkWrapper(world.getChunk(pos), world);
DimensionTypeWrapper dimType = DimensionTypeWrapper.getDimensionTypeWrapper(world.dimensionType());
// recreate the LOD where the blocks were changed
eventApi.blockChangeEvent(chunk, dimType);
}
private static final List<Integer> KEY_TO_CHECK_FOR = List.of(GLFW.GLFW_KEY_F6, GLFW.GLFW_KEY_F8);
HashSet<Integer> previousKeyDown = new HashSet<Integer>();
public void onKeyInput() {
ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
if (CONFIG.client().advanced().debugging().getDebugKeybindingsEnabled())
{
HashSet<Integer> currectKeyDown = new HashSet<Integer>();
// Note: Minecraft's InputConstants is same as GLFW Key values
//TODO: Use mixin to hook directly into the GLFW Keyboard event in minecraft KeyboardHandler
// Check all keys we need
for (int i = InputConstants.KEY_A; i <= InputConstants.KEY_Z; i++) {
if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), i)) {
currectKeyDown.add(i);
}
}
for (int i : KEY_TO_CHECK_FOR) {
if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), i)) {
currectKeyDown.add(i);
}
}
// Diff and trigger events
for (int c : currectKeyDown) {
if (!previousKeyDown.contains(c)) {
ClientApi.INSTANCE.keyPressedEvent(c);
}
}
// Update the set
previousKeyDown = currectKeyDown;
}
}
}
@@ -0,0 +1,96 @@
/*
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.fabric;
import com.seibel.lod.common.LodCommonMain;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.handlers.dependencyInjection.ModAccessorHandler;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
import com.seibel.lod.fabric.networking.NetworkHandler;
import com.seibel.lod.fabric.wrappers.modAccessor.ModChecker;
import com.seibel.lod.fabric.wrappers.modAccessor.OptifineAccessor;
import com.seibel.lod.fabric.wrappers.modAccessor.SodiumAccessor;
import com.seibel.lod.fabric.wrappers.modAccessor.StarlightAccessor;
import com.seibel.lod.fabric.wrappers.FabricDependencySetup;
import net.fabricmc.api.ClientModInitializer;
/**
* Initialize and setup the Mod. <br>
* If you are looking for the real start of the mod
* check out the ClientProxy.
*
* @author coolGi2007
* @author Ran
* @version 12-1-2021
*/
public class Main implements ClientModInitializer
{
// This is a client mod so it should implement ClientModInitializer and in fabric.mod.json it should have "environment": "client"
// Once it works on servers change the implement to ModInitializer and in fabric.mod.json it should be "environment": "*"
public static ClientProxy client_proxy;
// Do if implements ClientModInitializer
// This loads the mod before minecraft loads which causes a lot of issues
@Override
public void onInitializeClient() {
// no.
}
// This loads the mod after minecraft loads which doesn't causes a lot of issues
public static void init() {
LodCommonMain.initConfig();
LodCommonMain.startup(null, false, new NetworkHandler());
FabricDependencySetup.createInitialBindings();
FabricDependencySetup.finishBinding();
ApiShared.LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
// Check if this works
client_proxy = new ClientProxy();
client_proxy.registerEvents();
if (SingletonHandler.get(IModChecker.class).isModLoaded("sodium")) {
ModAccessorHandler.bind(ISodiumAccessor.class, new SodiumAccessor());
}
if (SingletonHandler.get(IModChecker.class).isModLoaded("starlight")) {
ModAccessorHandler.bind(IStarlightAccessor.class, new StarlightAccessor());
}
if (SingletonHandler.get(IModChecker.class).isModLoaded("optifine")) {
ModAccessorHandler.bind(IOptifineAccessor.class, new OptifineAccessor());
}
ModAccessorHandler.finishBinding();
}
public static void initServer() {
LodCommonMain.initConfig();
LodCommonMain.startup(null, true, new NetworkHandler());
FabricDependencySetup.createInitialBindings();
FabricDependencySetup.finishBinding();
ApiShared.LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
}
}
@@ -0,0 +1,16 @@
package com.seibel.lod.fabric.mixins;
import com.seibel.lod.fabric.Main;
import net.minecraft.server.dedicated.DedicatedServer;
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.CallbackInfoReturnable;
@Mixin(DedicatedServer.class)
public class MixinDedicatedServer {
@Inject(method = "initServer", at = @At("TAIL"))
public void initServer(CallbackInfoReturnable<Boolean> cir) {
Main.initServer();
}
}
@@ -0,0 +1,40 @@
package com.seibel.lod.fabric.mixins;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import net.minecraft.client.Camera;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.FogRenderer.FogMode;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.material.FogType;
@Mixin(FogRenderer.class)
public class MixinFogRenderer {
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
// Using this instead of Float.MAX_VALUE because Sodium don't like it.
private static final float A_REALLY_REALLY_BIG_VALUE = 420694206942069.F;
private static final float A_EVEN_LARGER_VALUE = 42069420694206942069.F;
@Inject(at = @At("RETURN"), method = "setupFog(Lnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/FogRenderer$FogMode;FZ)V")
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, CallbackInfo callback) {
FogType fogTypes = camera.getFluidInCamera();
Entity entity = camera.getEntity();
boolean isUnderWater = (entity instanceof LivingEntity) && ((LivingEntity)entity).hasEffect(MobEffects.BLINDNESS);
if (!isUnderWater) {
if (fogMode == FogMode.FOG_TERRAIN && fogTypes == FogType.NONE && CONFIG.client().graphics().fogQuality().getDisableVanillaFog()) {
RenderSystem.setShaderFogStart(A_REALLY_REALLY_BIG_VALUE);
RenderSystem.setShaderFogEnd(A_EVEN_LARGER_VALUE);
}
}
}
}
@@ -0,0 +1,21 @@
package com.seibel.lod.fabric.mixins;
import com.seibel.lod.fabric.Main;
import net.minecraft.client.Minecraft;
import net.minecraft.client.main.GameConfig;
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;
/**
* Loads the mod after minecraft loads.
* @author Ran
*/
@Mixin(value = Minecraft.class)
public class MixinMinecraft {
@Inject(method = "<init>", at = @At("TAIL"))
private void startMod(GameConfig gameConfig, CallbackInfo ci) {
Main.init();
}
}
@@ -1,34 +1,14 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.fabric.mixins;
package com.seibel.lod.mixins.client;
import com.seibel.lod.common.wrappers.gui.GetConfigScreen;
import com.seibel.lod.common.wrappers.gui.TexturedButtonWidget;
import com.seibel.lod.common.wrappers.config.ConfigGui;
import com.seibel.lod.common.wrappers.config.TexturedButtonWidget;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import net.minecraft.client.gui.screens.OptionsScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
#if PRE_MC_1_19
import net.minecraft.network.chat.TranslatableComponent;
#endif
import net.minecraft.resources.ResourceLocation;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -40,7 +20,7 @@ import java.util.Objects;
/**
* Adds a button to the menu to goto the config
*
* @author coolGi
* @author coolGi2007
* @version 12-02-2021
*/
@Mixin(OptionsScreen.class)
@@ -53,9 +33,8 @@ public class MixinOptionsScreen extends Screen {
@Inject(at = @At("HEAD"),method = "init")
private void lodconfig$init(CallbackInfo ci) {
if (Config.Client.optionsButton.get())
this. #if PRE_MC_1_17_1 addButton #else addRenderableWidget #endif
(new TexturedButtonWidget(
if (SingletonHandler.get(ILodConfigWrapperSingleton.class).client().getOptionsButton())
this.addRenderableWidget(new TexturedButtonWidget(
// Where the button is on the screen
this.width / 2 - 180, this.height / 6 - 12,
// Width and height of the button
@@ -66,12 +45,8 @@ public class MixinOptionsScreen extends Screen {
20, ICON_TEXTURE, 20, 40,
// Create the button and tell it where to go
// For now it goes to the client option by default
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(GetConfigScreen.getScreen(this)),
// Add a title to the utton
#if PRE_MC_1_19
new TranslatableComponent(ModInfo.ID + ".title")));
#else
Component.translatable(ModInfo.ID + ".title")));
#endif
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(ConfigGui.getScreen(this, "client")),
// Add a title to the screen
new TranslatableComponent("text.autoconfig." + ModInfo.ID + ".title")));
}
}
@@ -1,73 +1,50 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 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.lod.mixins.server;
package com.seibel.lod.fabric.mixins;
import java.util.concurrent.ExecutorService;
import java.util.function.Supplier;
import com.seibel.lod.FabricServerProxy;
import com.seibel.lod.fabric.ClientProxy;
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.CallbackInfoReturnable;
import com.seibel.lod.core.util.objects.DummyRunExecutorService;
import com.seibel.lod.core.util.DummyRunExecutorService;
import net.minecraft.Util;
@Mixin(Util.class)
public class MixinUtilBackgroundThread
public class MixinUtilBackgroudThread
{
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
{
if (FabricServerProxy.isGenerationThreadChecker != null && FabricServerProxy.isGenerationThreadChecker.get())
{
//ApiShared.LOGGER.info("util backgroundExecutor triggered");
ci.setReturnValue(new DummyRunExecutorService());
}
}
#if POST_MC_1_17_1
@Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/lang/Runnable;)Ljava/lang/Runnable;",
at = @At("HEAD"), cancellable = true)
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable<Runnable> ci)
{
if (FabricServerProxy.isGenerationThreadChecker != null && FabricServerProxy.isGenerationThreadChecker.get())
if (ClientProxy.isGenerationThreadChecker != null && ClientProxy.isGenerationThreadChecker.get())
{
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
ci.setReturnValue(r);
}
}
#endif
#if POST_MC_1_18_1
@Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/util/function/Supplier;)Ljava/util/function/Supplier;",
at = @At("HEAD"), cancellable = true)
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
{
if (FabricServerProxy.isGenerationThreadChecker != null && FabricServerProxy.isGenerationThreadChecker.get())
if (ClientProxy.isGenerationThreadChecker != null && ClientProxy.isGenerationThreadChecker.get())
{
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
ci.setReturnValue(r);
}
}
#endif
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
{
if (ClientProxy.isGenerationThreadChecker != null && ClientProxy.isGenerationThreadChecker.get())
{
//ApiShared.LOGGER.info("util backgroundExecutor triggered");
ci.setReturnValue(new DummyRunExecutorService());
}
}
}

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