Compare commits
477 Commits
2.1.0a
...
serverside
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a771a3e21 | |||
| 0aa109a341 | |||
| 6d44255175 | |||
| f8bb35cb2b | |||
| 52f1aed124 | |||
| 6ae1ba1e17 | |||
| 9105f30fec | |||
| 839c849a9d | |||
| d208b0ab19 | |||
| ab4ef429db | |||
| 86473e022e | |||
| 275f507096 | |||
| fd89f569d0 | |||
| eefc765823 | |||
| ebccb2516b | |||
| 8c62a40da9 | |||
| d56af5c38f | |||
| 39b1ec61ba | |||
| cb613cf7df | |||
| 28e33b4c36 | |||
| 855e6b8180 | |||
| d62161f529 | |||
| 01c5a4072a | |||
| 71d48411f1 | |||
| 731842e09c | |||
| 61169f87c0 | |||
| 1697707114 | |||
| 9fb3b196d2 | |||
| 34b0b7dc31 | |||
| 867b875cf9 | |||
| 691e1022e3 | |||
| 18fd157474 | |||
| 4948158fa8 | |||
| e3b972c928 | |||
| ad056cb64e | |||
| 3e22ddead5 | |||
| 5c7e27c52d | |||
| 3a5c6f12c0 | |||
| 627eee7a6d | |||
| 3875c8c4ce | |||
| 89b959d3f5 | |||
| d62e50d6f4 | |||
| 7c4c99089b | |||
| 16836a2b49 | |||
| f5651f26a5 | |||
| 82ff59c857 | |||
| 8af61041f0 | |||
| 2a9136b56f | |||
| 00ec14d319 | |||
| 56188bc7d2 | |||
| 64da6c811d | |||
| e6b93e0d92 | |||
| f874219a64 | |||
| b4822740f4 | |||
| af205a50b4 | |||
| 2f6eaf79bd | |||
| 625f1e700f | |||
| 897d5b0b11 | |||
| 95641e2f4e | |||
| cd856b86c7 | |||
| c00aa6d627 | |||
| 9b2429d388 | |||
| 2aa68ec41d | |||
| 398a3fb0bc | |||
| 13c9f95750 | |||
| b0549cecff | |||
| 95fb4a0e6a | |||
| 2a3aadc2fa | |||
| e0fa638ad9 | |||
| 4e42cbd4ce | |||
| 52bddca0df | |||
| b6c6be77cd | |||
| 0964293a72 | |||
| 606dede9ef | |||
| e8c9d8391a | |||
| c8b6141ce0 | |||
| 948540369f | |||
| 363df0ad6f | |||
| a37e105434 | |||
| aeea0c00c3 | |||
| 88ca223bbc | |||
| 137352674e | |||
| 4734552954 | |||
| 879c2f1ec4 | |||
| 7dc9d2a352 | |||
| 4a51bbc796 | |||
| cabc470ebd | |||
| 0bf1f493aa | |||
| 705bd14ee4 | |||
| 155955e49b | |||
| c76a793b18 | |||
| 50cc8501a0 | |||
| 209279e3e4 | |||
| 41239572a5 | |||
| 94ca0e2729 | |||
| 106ab47c3d | |||
| a84f9b60e5 | |||
| 5befdbcddc | |||
| 4481e8634a | |||
| 3e02d7f9dc | |||
| 48b38d9285 | |||
| 8c7c787a8f | |||
| 3e432682fb | |||
| fc0cf56b48 | |||
| 05569c03a4 | |||
| 32c63ae15b | |||
| 2d567b84be | |||
| e2a378250f | |||
| e2083a1836 | |||
| 334946ab59 | |||
| 8c9bb98125 | |||
| 726f0f3d3c | |||
| 50e5898692 | |||
| de05a5f674 | |||
| 31b57fae50 | |||
| bbf62f7ee3 | |||
| 6211542708 | |||
| a2d5e8cdb3 | |||
| 692b304898 | |||
| 2f686057f3 | |||
| 132251341f | |||
| 2bac5f933a | |||
| 2e565aa83a | |||
| 4e9d0f4861 | |||
| 7216b193e8 | |||
| 0ca93e311c | |||
| c33a5bf814 | |||
| 97756a5196 | |||
| c7aab012ae | |||
| 377f7d23e3 | |||
| 7005202384 | |||
| 99e8f57bac | |||
| afddf4168e | |||
| fbffdc0c9f | |||
| e6d3647490 | |||
| 13363ff363 | |||
| 7f98e4b1eb | |||
| 408460b0ae | |||
| b69ef5835d | |||
| 0428fa0912 | |||
| 9f3124fa56 | |||
| fbbdab73c6 | |||
| 80ccab21da | |||
| ee9441c521 | |||
| a9e0fd5d9b | |||
| 98464889ca | |||
| eed5fd60c6 | |||
| ac43cd5496 | |||
| 1f16a7c808 | |||
| 39e4c70754 | |||
| 82eb27af4c | |||
| 663ce3cde6 | |||
| 43fee18ae4 | |||
| 3aaab94b39 | |||
| 07a0779ca4 | |||
| 014310631e | |||
| 2adba02a38 | |||
| 9dd76db3fc | |||
| 97dacf2429 | |||
| 1c189e162a | |||
| f7a0fff869 | |||
| 4f7e934c98 | |||
| 2f985d0926 | |||
| 563dcd7de6 | |||
| 2a3c544fba | |||
| 0a5cc734de | |||
| 09d133b994 | |||
| 26a4223ecf | |||
| e2943fdcaf | |||
| f1053251b4 | |||
| be1dcaf43c | |||
| 0da158fecc | |||
| a7e8bbaf6a | |||
| a899d988fc | |||
| 06b5b2c514 | |||
| 864a19b79f | |||
| 8974323406 | |||
| 46c9e0103a | |||
| 02203466ed | |||
| 87b22ea1cc | |||
| d26327a930 | |||
| 469d2bdcb7 | |||
| 80732943c8 | |||
| 5516603a0c | |||
| b737adc3da | |||
| 994c86d5ba | |||
| 18ccbbbb8e | |||
| 31c3fb9a1e | |||
| 8bdb383b2e | |||
| d13ec687ed | |||
| 43069703cd | |||
| 6d76ace604 | |||
| 9b139575e7 | |||
| efb9129edf | |||
| 6a380f6a7b | |||
| f3a8afeee3 | |||
| a4501f86e9 | |||
| 095fff96ff | |||
| a23211d061 | |||
| b57ea41686 | |||
| 62fb5ffb73 | |||
| 99c713967b | |||
| 0798ca01c5 | |||
| 9f3de07bd8 | |||
| cd74117de3 | |||
| e7d7033548 | |||
| 8bfc1430c8 | |||
| 34db7c9dac | |||
| 272841aae9 | |||
| 389b09a5cd | |||
| 84bd876c71 | |||
| 7e45051ffd | |||
| 5570f3a313 | |||
| f4e71f7012 | |||
| 601d4e6e3a | |||
| a12092c1a1 | |||
| bd6621183d | |||
| 94ad118c5d | |||
| 48e2978438 | |||
| ccc8076c66 | |||
| 96b4c1a9e8 | |||
| cc4a69c10c | |||
| 7293677ddb | |||
| 0f2ff20375 | |||
| 004103551f | |||
| ea47e11ecf | |||
| 8a3837b04b | |||
| edfeaa618b | |||
| 961cdbe868 | |||
| ff6ab67b69 | |||
| c01fb4a716 | |||
| 8bd524791f | |||
| 7706240acb | |||
| 4cf48fd997 | |||
| 2708c1ee11 | |||
| ebb0f6ebad | |||
| 2c263a2549 | |||
| 955524c632 | |||
| 564e0d3263 | |||
| c533b2e8ea | |||
| 6073d8122a | |||
| 26059d5656 | |||
| 3f23281e8d | |||
| fb25423deb | |||
| 6928c8dc28 | |||
| 7dfe0e4c50 | |||
| 1429ae5434 | |||
| 3fb4d5a233 | |||
| 872226e5c5 | |||
| fb46820b1f | |||
| a786678bcb | |||
| 0d35a3ea8e | |||
| 6f87e22048 | |||
| 7c07c1e5bd | |||
| 4ddb9659f5 | |||
| e74b8c89ba | |||
| 1b536e4aef | |||
| 335f11acd3 | |||
| b55b560cce | |||
| d87a152052 | |||
| db5a9c7c84 | |||
| 2508efdd91 | |||
| 4852720e14 | |||
| f39d156b11 | |||
| e21eb61335 | |||
| c49f385e3c | |||
| 0584b0e593 | |||
| 220ac89ad8 | |||
| e8e56b66a3 | |||
| 634d8a5b52 | |||
| b621c9fb8d | |||
| 696f84a064 | |||
| 5c13ff8960 | |||
| e102cd78cd | |||
| c5a782acba | |||
| 2008ea2b0c | |||
| 0f349461d9 | |||
| baf464aa02 | |||
| 51d83d803a | |||
| 2b3244159b | |||
| 9255c22d0e | |||
| 4d573c4aea | |||
| a59f359133 | |||
| c83d02c30c | |||
| d01573b03e | |||
| b1fb74539f | |||
| 40962ec9ba | |||
| 0515ac2919 | |||
| 8072695391 | |||
| 2c140bf7d7 | |||
| d3e88b40f4 | |||
| 5e0e15777c | |||
| b57fc5c9aa | |||
| 91ea68075e | |||
| 0840ec8b00 | |||
| d9f37ad7d6 | |||
| 992a7129e5 | |||
| 1d5ea329de | |||
| 00d0a0d2fc | |||
| 95d4314982 | |||
| b588b937ea | |||
| f524ad027e | |||
| b3111b9548 | |||
| 6c38cb3dee | |||
| d75b2dfc1c | |||
| a5b44d65c6 | |||
| 7a1c61405c | |||
| bcb8794d30 | |||
| f9775b115e | |||
| a56a2c2ba3 | |||
| b2efb33a5b | |||
| 5928cfe4b4 | |||
| 234204590f | |||
| e3838c560a | |||
| 6cbc9db1d8 | |||
| 127dcfcb46 | |||
| d1abdd822d | |||
| 85b7ccb38e | |||
| fc157b738e | |||
| 977afffe98 | |||
| 180b22f21a | |||
| d0330ad62f | |||
| 4d22b18f3c | |||
| df797b240e | |||
| a50ef86302 | |||
| 4aede27d75 | |||
| e616c63ebe | |||
| 03ec333a26 | |||
| 27446965db | |||
| c6d7313225 | |||
| 160912a17a | |||
| d408aacbc8 | |||
| 4889287e69 | |||
| 6acdfabb7f | |||
| 3c01d00772 | |||
| 736bb022d2 | |||
| e92130d6cc | |||
| a44dfa92a6 | |||
| 4c8ee862e5 | |||
| 73b89fe573 | |||
| fed2600dbe | |||
| 1d7d94cfec | |||
| 5577261774 | |||
| bf0f3131a0 | |||
| 1b98ea59d7 | |||
| c38efd9d6b | |||
| 4889119061 | |||
| accb2d6af3 | |||
| 24b426a17b | |||
| 8c1bccb430 | |||
| 3cb2a70f4d | |||
| a313cb3db1 | |||
| c29c6d1870 | |||
| b4a64b0c3d | |||
| 1439ca5c08 | |||
| 97ad3bc78f | |||
| b59d8cff8d | |||
| 0e93aa4aea | |||
| 28f8099777 | |||
| c83b0ae533 | |||
| 5ceeebe567 | |||
| e8db9803be | |||
| f009fd41ab | |||
| 9faa3b0a54 | |||
| 0e70478dd3 | |||
| 309b6c6013 | |||
| f20af18b62 | |||
| 7d3329fd98 | |||
| 9a880c3ab1 | |||
| 0b247f04b4 | |||
| 7f1d664731 | |||
| a2288d740b | |||
| 958f0347a3 | |||
| 859bb2e34e | |||
| a2acd08e0d | |||
| b986583fc4 | |||
| c6355f96a6 | |||
| 723d171746 | |||
| 63098d8519 | |||
| 44b743267b | |||
| 720155c408 | |||
| 334b487e23 | |||
| 6e674f3732 | |||
| d130a602d6 | |||
| 8d1ff02937 | |||
| 15b1603e35 | |||
| 4ad0a22db7 | |||
| 35bc1df32c | |||
| bb2a1158c2 | |||
| 76f6f6f746 | |||
| 3b771b5300 | |||
| 9497918e06 | |||
| e52c5d5c67 | |||
| 1ce4750dfc | |||
| 2b371340ff | |||
| e8d906b407 | |||
| 572973c69a | |||
| 9f2d6b9c78 | |||
| 54277040e9 | |||
| bbe333fab7 | |||
| 37fed5a924 | |||
| 5fc29334cd | |||
| 9d32e92e0a | |||
| b08ee76a00 | |||
| 2a4cc6e63d | |||
| 6b2560f98b | |||
| 08111d8874 | |||
| 80f48cd5a4 | |||
| 40cd6c1386 | |||
| e9a13dffb8 | |||
| 22680baad7 | |||
| cca480e5d8 | |||
| 249c3423d9 | |||
| 15cb6468d9 | |||
| f24019d648 | |||
| 733d03c630 | |||
| c3e84648f1 | |||
| 76c33b6b58 | |||
| 26a947ea13 | |||
| 91334c0e5c | |||
| 172b05aeac | |||
| b84e5ca265 | |||
| 20ef5a10fc | |||
| 33640fd35d | |||
| e5f7c5728f | |||
| 5a9bbf9829 | |||
| 23ca022ee9 | |||
| 6c80165523 | |||
| d598061fa7 | |||
| 02498aa189 | |||
| d535f6aa57 | |||
| 933753a38a | |||
| 5483cdbc51 | |||
| 1ea62fd5ec | |||
| aaf0361c50 | |||
| a08feebde0 | |||
| f7131fd2ca | |||
| 2100f4a6fe | |||
| 996f097b9d | |||
| 2e1d737268 | |||
| d374870fb7 | |||
| 5c303df32c | |||
| dfc4b51e89 | |||
| 765202d582 | |||
| 0d2e5adbed | |||
| 68e9d64779 | |||
| b64b44f301 | |||
| 8c07bb37f3 | |||
| c1f6c2dbbd | |||
| 2eb1c16837 | |||
| e5fb8477d3 | |||
| 428cacd262 | |||
| 76926d38db | |||
| 9fec679b03 | |||
| 853a1d1490 | |||
| 01273e31bc | |||
| ebb4808bdc | |||
| fd09adb1a7 | |||
| 82b7b439a4 | |||
| f1b3ae120b | |||
| 70ee20e817 | |||
| f713d65f9c | |||
| c2b98ef694 | |||
| 140c9f6a50 | |||
| c704d61d03 | |||
| aae484fbdf | |||
| a546a97e34 | |||
| 3ca9d98c05 | |||
| 460b73e35c | |||
| 8901a191d9 | |||
| 1bbe35c9f1 | |||
| f92e957826 | |||
| 636e6736a3 | |||
| 8e29f65815 | |||
| a9309078f3 | |||
| 9692e978de | |||
| 914372b858 |
+2
-2
@@ -538,7 +538,7 @@ ij_groovy_wrap_chain_calls_after_dot = false
|
|||||||
ij_groovy_wrap_long_lines = false
|
ij_groovy_wrap_long_lines = false
|
||||||
|
|
||||||
[{*.har,*.json,*.png.mcmeta,mcmod.info,pack.mcmeta}]
|
[{*.har,*.json,*.png.mcmeta,mcmod.info,pack.mcmeta}]
|
||||||
indent_size = 4
|
indent_size = 2
|
||||||
ij_json_array_wrapping = split_into_lines
|
ij_json_array_wrapping = split_into_lines
|
||||||
ij_json_keep_blank_lines_in_code = 0
|
ij_json_keep_blank_lines_in_code = 0
|
||||||
ij_json_keep_indents_on_empty_lines = false
|
ij_json_keep_indents_on_empty_lines = false
|
||||||
@@ -688,7 +688,7 @@ ij_markdown_wrap_text_inside_blockquotes = true
|
|||||||
ij_toml_keep_indents_on_empty_lines = false
|
ij_toml_keep_indents_on_empty_lines = false
|
||||||
|
|
||||||
[{*.yaml,*.yml}]
|
[{*.yaml,*.yml}]
|
||||||
indent_size = 4
|
indent_size = 2
|
||||||
ij_yaml_align_values_properties = do_not_align
|
ij_yaml_align_values_properties = do_not_align
|
||||||
ij_yaml_autoinsert_sequence_marker = true
|
ij_yaml_autoinsert_sequence_marker = true
|
||||||
ij_yaml_block_mapping_on_new_line = false
|
ij_yaml_block_mapping_on_new_line = false
|
||||||
|
|||||||
+9
-4
@@ -18,19 +18,24 @@ variables:
|
|||||||
.build_java:
|
.build_java:
|
||||||
#image: eclipse-temurin:17
|
#image: eclipse-temurin:17
|
||||||
cache:
|
cache:
|
||||||
key: "gradleCache"
|
key: "gradleCache_$CI_JOB_NAME_SLUG"
|
||||||
policy: pull-push
|
policy: pull-push
|
||||||
paths:
|
paths:
|
||||||
- .gradle
|
- .gradle
|
||||||
- cache/
|
- cache/
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
|
retry:
|
||||||
|
max: 2
|
||||||
|
when:
|
||||||
|
- runner_system_failure
|
||||||
|
- stuck_or_timeout_failure
|
||||||
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
stage: build
|
stage: build
|
||||||
parallel:
|
parallel:
|
||||||
matrix:
|
matrix:
|
||||||
- MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6"]
|
- MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6", "1.21.1"]
|
||||||
script:
|
script:
|
||||||
# this both runs the unit tests and assembles the code
|
# this both runs the unit tests and assembles the code
|
||||||
- ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
|
- ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
|
||||||
@@ -63,7 +68,7 @@ build:
|
|||||||
extends: .build_java
|
extends: .build_java
|
||||||
|
|
||||||
|
|
||||||
api:
|
.api:
|
||||||
stage: api
|
stage: api
|
||||||
needs: []
|
needs: []
|
||||||
script:
|
script:
|
||||||
@@ -87,7 +92,7 @@ api:
|
|||||||
|
|
||||||
|
|
||||||
# generate and publish API javadocs
|
# generate and publish API javadocs
|
||||||
pages:
|
.pages:
|
||||||
stage: pages
|
stage: pages
|
||||||
needs: []
|
needs: []
|
||||||
script:
|
script:
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Fabric Client & Server" type="CompoundRunConfigurationType">
|
||||||
|
<toRun name="Fabric Client (:fabric)" type="Application" />
|
||||||
|
<toRun name="Fabric Server (:fabric)" type="Application" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Forge Client & Server" type="CompoundRunConfigurationType">
|
||||||
|
<toRun name="Forge Client (gradle)" type="GradleRunConfiguration" />
|
||||||
|
<toRun name="Forge Server (gradle)" type="GradleRunConfiguration" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Forge Client (gradle)" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="forge:runClient" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<RunAsTest>false</RunAsTest>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Forge Server (gradle)" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="forge:runServer" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<RunAsTest>false</RunAsTest>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Neoforge Client & Server" type="CompoundRunConfigurationType">
|
||||||
|
<toRun name="Neoforge Client (gradle)" type="GradleRunConfiguration" />
|
||||||
|
<toRun name="Neoforge Server (gradle)" type="GradleRunConfiguration" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Neoforge Client (gradle)" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="neoforge:runClient" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<RunAsTest>false</RunAsTest>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Neoforge Server (gradle)" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="neoforge:runServer" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<RunAsTest>false</RunAsTest>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
+23
-18
@@ -54,7 +54,7 @@ def writeBuildGradlePredefine(List<String> mcVers, int mcIndex)
|
|||||||
// Transfers the values set in settings.gradle to the rest of the project
|
// Transfers the values set in settings.gradle to the rest of the project
|
||||||
project.gradle.ext.getProperties().each { prop ->
|
project.gradle.ext.getProperties().each { prop ->
|
||||||
rootProject.ext.set(prop.key, prop.value)
|
rootProject.ext.set(prop.key, prop.value)
|
||||||
// println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
|
//println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
|
||||||
}
|
}
|
||||||
// Sets up manifold stuff
|
// Sets up manifold stuff
|
||||||
writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
|
writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
|
||||||
@@ -106,11 +106,12 @@ subprojects { p ->
|
|||||||
apply plugin: "systems.manifold.manifold-gradle-plugin"
|
apply plugin: "systems.manifold.manifold-gradle-plugin"
|
||||||
|
|
||||||
// Apply forge's loom
|
// Apply forge's loom
|
||||||
if (
|
if ((findProject(":forge") && p == project(":forge")) ||
|
||||||
(findProject(":forge") && p == project(":forge")) ||
|
(findProject(":neoforge") && p == project(":neoforge"))
|
||||||
(findProject(":neoforge") && p == project(":neoforge"))
|
)
|
||||||
)
|
{
|
||||||
apply plugin: "dev.architectury.loom"
|
apply plugin: "dev.architectury.loom"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Set the manifold version (may not be required tough)
|
// Set the manifold version (may not be required tough)
|
||||||
@@ -217,8 +218,7 @@ subprojects { p ->
|
|||||||
// forgeShadowMe("com.formdev:svgSalamander:${rootProject.svgSalamander_version}")
|
// forgeShadowMe("com.formdev:svgSalamander:${rootProject.svgSalamander_version}")
|
||||||
|
|
||||||
// Netty
|
// Netty
|
||||||
// Breaks 1.16.5
|
implementation("io.netty:netty-buffer:${rootProject.netty_version}")
|
||||||
//forgeShadowMe("io.netty:netty-all:${rootProject.netty_version}")
|
|
||||||
|
|
||||||
// Remember, for lwjgl dependencies that arent included in Minecraft, you need to also need to add it to the ShadowJar thing
|
// Remember, for lwjgl dependencies that arent included in Minecraft, you need to also need to add it to the ShadowJar thing
|
||||||
forgeShadowMe("org.lwjgl:lwjgl-jawt:${rootProject.lwjgl_version}") {
|
forgeShadowMe("org.lwjgl:lwjgl-jawt:${rootProject.lwjgl_version}") {
|
||||||
@@ -306,7 +306,8 @@ subprojects { p ->
|
|||||||
// relocate "com.kitfox.svg", "${librariesLocation}.kitfox.svg"
|
// relocate "com.kitfox.svg", "${librariesLocation}.kitfox.svg"
|
||||||
|
|
||||||
// Netty
|
// Netty
|
||||||
relocate "io.netty", "${librariesLocation}.netty"
|
// Don't relocate, it causes problems with using MC's FriendlyByteBufs
|
||||||
|
// relocate "io.netty", "${librariesLocation}.netty"
|
||||||
|
|
||||||
mergeServiceFiles()
|
mergeServiceFiles()
|
||||||
}
|
}
|
||||||
@@ -328,7 +329,7 @@ subprojects { p ->
|
|||||||
"META-INF/neoforge.mods.toml",
|
"META-INF/neoforge.mods.toml",
|
||||||
|
|
||||||
// The mixins for each of the loaders
|
// The mixins for each of the loaders
|
||||||
"DistantHorizons."+ p.name +".fabricLike.mixins.json"
|
"DistantHorizons." + p.name + ".fabricLike.mixins.json"
|
||||||
]
|
]
|
||||||
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
||||||
|
|
||||||
@@ -430,9 +431,11 @@ subprojects { p ->
|
|||||||
jar {
|
jar {
|
||||||
from "LICENSE.txt"
|
from "LICENSE.txt"
|
||||||
manifest {
|
manifest {
|
||||||
attributes 'Implementation-Title': rootProject.mod_name,
|
attributes(
|
||||||
'Implementation-Version': rootProject.mod_version,
|
'Implementation-Title': rootProject.mod_name,
|
||||||
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain' // When changing the main of the jar change this line
|
'Implementation-Version': rootProject.mod_version,
|
||||||
|
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain' // When changing the main of the jar change this line
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,14 +524,16 @@ allprojects { p ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Required for ModMenu
|
// VanillaGradle and Mixins in common
|
||||||
maven { url "https://maven.terraformersmc.com/" }
|
|
||||||
|
|
||||||
// Required for Mixins & VanillaGradle
|
|
||||||
maven { url "https://repo.spongepowered.org/maven/" }
|
maven { url "https://repo.spongepowered.org/maven/" }
|
||||||
|
|
||||||
// Required for Canvas (mod)
|
// Canvas mod
|
||||||
maven { url "https://maven.vram.io/" }
|
maven { url "https://maven.vram.io/" }
|
||||||
|
// ModMenu mod
|
||||||
|
maven { url "https://maven.terraformersmc.com/" }
|
||||||
|
|
||||||
|
// neoforge
|
||||||
|
maven { url "https://maven.neoforged.net/releases/" }
|
||||||
|
|
||||||
// These 3 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
|
// These 3 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
|
||||||
flatDir {
|
flatDir {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ===================="
|
echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ===================="
|
||||||
mkdir -p buildAllJars | true
|
mkdir -p buildAllJars
|
||||||
|
rm -rf buildAllJars/*
|
||||||
|
|
||||||
# Loop trough everything in the version properties folder
|
# Loop trough everything in the version properties folder
|
||||||
for d in versionProperties/*; do
|
for d in versionProperties/*; do
|
||||||
@@ -11,12 +12,17 @@ for d in versionProperties/*; do
|
|||||||
# Clean out the folders, build it, and merge it
|
# Clean out the folders, build it, and merge it
|
||||||
# (We could use "./" to run gradlew, but as it is a shell script im going to be running it with the "sh" command)
|
# (We could use "./" to run gradlew, but as it is a shell script im going to be running it with the "sh" command)
|
||||||
echo "==================== Cleaning workspace to build $version ===================="
|
echo "==================== Cleaning workspace to build $version ===================="
|
||||||
sh gradlew clean -PmcVer=$version --no-daemon || true
|
sh gradlew clean -PmcVer=$version
|
||||||
|
if [ $? != 0 ]; then continue; fi
|
||||||
|
|
||||||
echo "====================Building $version ===================="
|
echo "====================Building $version ===================="
|
||||||
sh gradlew build -PmcVer=$version --no-daemon || true
|
sh gradlew build -PmcVer=$version
|
||||||
|
if [ $? != 0 ]; then continue; fi
|
||||||
|
|
||||||
echo "==================== Merging $version ===================="
|
echo "==================== Merging $version ===================="
|
||||||
sh gradlew mergeJars -PmcVer=$version --no-daemon || true
|
sh gradlew mergeJars -PmcVer=$version
|
||||||
|
if [ $? != 0 ]; then continue; fi
|
||||||
|
|
||||||
echo "==================== Moving jar ===================="
|
echo "==================== Moving jar ===================="
|
||||||
mv Merged/*.jar buildAllJars/ || true
|
mv Merged/*.jar buildAllJars/
|
||||||
# The "| true" at the end of those are just to make sure the script continues even if a build fails
|
|
||||||
done
|
done
|
||||||
|
|||||||
+16
-1
@@ -1,3 +1,19 @@
|
|||||||
|
buildscript {
|
||||||
|
configurations.configureEach {
|
||||||
|
resolutionStrategy {
|
||||||
|
force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// temporary fix for broken spongepowered version
|
||||||
|
buildscript {
|
||||||
|
configurations.configureEach {
|
||||||
|
resolutionStrategy {
|
||||||
|
force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "org.spongepowered.gradle.vanilla" version "0.2.1-SNAPSHOT"
|
id "org.spongepowered.gradle.vanilla" version "0.2.1-SNAPSHOT"
|
||||||
@@ -27,4 +43,3 @@ publishing {
|
|||||||
// Add repositories to publish to here.
|
// Add repositories to publish to here.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+167
-11
@@ -1,18 +1,30 @@
|
|||||||
package com.seibel.distanthorizons.common;
|
package com.seibel.distanthorizons.common;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.Command;
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import com.mojang.brigadier.arguments.*;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
|
||||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
|
||||||
import com.seibel.distanthorizons.common.wrappers.DependencySetup;
|
import com.seibel.distanthorizons.common.wrappers.DependencySetup;
|
||||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
||||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
import com.seibel.distanthorizons.core.config.ConfigBase;
|
import com.seibel.distanthorizons.core.config.ConfigBase;
|
||||||
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
|
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
|
||||||
|
import com.seibel.distanthorizons.core.config.types.AbstractConfigType;
|
||||||
|
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.core.jar.ModJarInfo;
|
import com.seibel.distanthorizons.core.jar.ModJarInfo;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.base.CodecCrashMessage;
|
||||||
|
import com.seibel.distanthorizons.core.util.objects.Pair;
|
||||||
|
import com.seibel.distanthorizons.core.world.DhServerWorld;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||||
@@ -23,9 +35,25 @@ import net.minecraft.server.dedicated.DedicatedServer;
|
|||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static com.mojang.brigadier.arguments.DoubleArgumentType.doubleArg;
|
||||||
|
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
|
||||||
|
import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_ENABLE_CODEC_CRASH_MESSAGE;
|
||||||
|
import static net.minecraft.commands.Commands.argument;
|
||||||
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_19_2
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
#else // < 1.19.2
|
||||||
|
import net.minecraft.network.chat.TranslatableComponent;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base for all mod loader initializers
|
* Base for all mod loader initializers
|
||||||
* and handles most setup.
|
* and handles most setup.
|
||||||
@@ -67,7 +95,7 @@ public abstract class AbstractModInitializer
|
|||||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
|
||||||
|
|
||||||
this.startup();
|
this.startup();
|
||||||
this.printModInfo(true);
|
this.printModInfo();
|
||||||
|
|
||||||
this.createClientProxy().registerEvents();
|
this.createClientProxy().registerEvents();
|
||||||
this.createServerProxy(false).registerEvents();
|
this.createServerProxy(false).registerEvents();
|
||||||
@@ -91,7 +119,7 @@ public abstract class AbstractModInitializer
|
|||||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
|
||||||
|
|
||||||
this.startup();
|
this.startup();
|
||||||
this.printModInfo(false);
|
this.printModInfo();
|
||||||
|
|
||||||
// This prevents returning uninitialized Config values,
|
// This prevents returning uninitialized Config values,
|
||||||
// resulting from a circular reference mid-initialization in a static class
|
// resulting from a circular reference mid-initialization in a static class
|
||||||
@@ -100,6 +128,8 @@ public abstract class AbstractModInitializer
|
|||||||
|
|
||||||
this.createServerProxy(true).registerEvents();
|
this.createServerProxy(true).registerEvents();
|
||||||
|
|
||||||
|
this.initializeModCompat();
|
||||||
|
|
||||||
LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
|
LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
|
||||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
|
||||||
|
|
||||||
@@ -130,17 +160,14 @@ public abstract class AbstractModInitializer
|
|||||||
this.createInitialBindings();
|
this.createInitialBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printModInfo(boolean printGitInfo)
|
private void printModInfo()
|
||||||
{
|
{
|
||||||
LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
|
LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
|
||||||
|
|
||||||
if (printGitInfo)
|
// Useful for dev builds
|
||||||
{
|
LOGGER.info("DH Branch: " + ModJarInfo.Git_Branch);
|
||||||
// Useful for dev builds
|
LOGGER.info("DH Commit: " + ModJarInfo.Git_Commit);
|
||||||
LOGGER.info("DH Branch: " + ModJarInfo.Git_Branch);
|
LOGGER.info("DH Jar Build Source: " + ModJarInfo.Build_Source);
|
||||||
LOGGER.info("DH Commit: " + ModJarInfo.Git_Commit);
|
|
||||||
LOGGER.info("DH Jar Build Source: " + ModJarInfo.Build_Source);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T extends IModAccessor> void tryCreateModCompatAccessor(String modId, Class<? super T> accessorClass, Supplier<T> accessorConstructor)
|
protected <T extends IModAccessor> void tryCreateModCompatAccessor(String modId, Class<? super T> accessorClass, Supplier<T> accessorConstructor)
|
||||||
@@ -166,7 +193,136 @@ public abstract class AbstractModInitializer
|
|||||||
LOGGER.info("Mod Post-Initialized");
|
LOGGER.info("Mod Post-Initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initCommands() { /* currently unimplemented */ }
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
private void initCommands()
|
||||||
|
{
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> builder = literal("dhconfig")
|
||||||
|
.requires(source -> source.hasPermission(4));
|
||||||
|
|
||||||
|
for (AbstractConfigType<?, ?> type : ConfigBase.INSTANCE.entries)
|
||||||
|
{
|
||||||
|
if (!(type instanceof ConfigEntry))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//noinspection PatternVariableCanBeUsed
|
||||||
|
ConfigEntry configEntry = (ConfigEntry) type;
|
||||||
|
if (configEntry.getServersideShortName() == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Function<
|
||||||
|
Function<CommandContext<CommandSourceStack>, Object>,
|
||||||
|
Command<CommandSourceStack>
|
||||||
|
> makeConfigUpdater = getter -> c -> {
|
||||||
|
Object value = getter.apply(c);
|
||||||
|
|
||||||
|
c.getSource().sendSuccess(
|
||||||
|
#if MC_VER >= MC_1_20_1
|
||||||
|
() -> Component.literal("Changed the value of "+configEntry.getServersideShortName()+" to "+value),
|
||||||
|
#elif MC_VER >= MC_1_19_2
|
||||||
|
Component.literal("Changed the value of "+configEntry.getServersideShortName()+" to "+value),
|
||||||
|
#else
|
||||||
|
new TranslatableComponent("Changed the value of "+configEntry.getServersideShortName()+" to "+value),
|
||||||
|
#endif
|
||||||
|
true);
|
||||||
|
configEntry.set(value);
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> subcommand = literal(configEntry.getServersideShortName())
|
||||||
|
.executes(c -> {
|
||||||
|
#if MC_VER >= MC_1_20_1
|
||||||
|
c.getSource().sendSuccess(() -> Component.literal("Current value of "+configEntry.getServersideShortName()+" is "+configEntry.get()), true);
|
||||||
|
#elif MC_VER >= MC_1_19_2
|
||||||
|
c.getSource().sendSuccess(Component.literal("Current value of "+configEntry.getServersideShortName()+" is "+configEntry.get()), true);
|
||||||
|
#else // < 1.19.2
|
||||||
|
c.getSource().sendSuccess(new TranslatableComponent("Current value of "+configEntry.getServersideShortName()+" is "+configEntry.get()), true);
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Enum.class.isAssignableFrom(configEntry.getType()))
|
||||||
|
{
|
||||||
|
for (Object choice : configEntry.getType().getEnumConstants())
|
||||||
|
{
|
||||||
|
subcommand.then(
|
||||||
|
literal(choice.toString())
|
||||||
|
.executes(makeConfigUpdater.apply(c -> choice))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
boolean setterAdded = false;
|
||||||
|
|
||||||
|
for (java.util.Map.Entry<Class<?>, Pair<Supplier<ArgumentType<?>>, BiFunction<CommandContext<?>, String, ?>>> pair : new HashMap<
|
||||||
|
Class<?>,
|
||||||
|
Pair<
|
||||||
|
Supplier<ArgumentType<?>>,
|
||||||
|
BiFunction<CommandContext<?>, String, ?>>
|
||||||
|
>() {{
|
||||||
|
this.put(Integer.class, new Pair<>(() -> integer((int) configEntry.getMin(), (int) configEntry.getMax()), IntegerArgumentType::getInteger));
|
||||||
|
this.put(Double.class, new Pair<>(() -> doubleArg((double) configEntry.getMin(), (double) configEntry.getMax()), DoubleArgumentType::getDouble));
|
||||||
|
this.put(Boolean.class, new Pair<>(BoolArgumentType::bool, BoolArgumentType::getBool));
|
||||||
|
this.put(String.class, new Pair<>(StringArgumentType::string, StringArgumentType::getString));
|
||||||
|
}}.entrySet())
|
||||||
|
{
|
||||||
|
if (!pair.getKey().isAssignableFrom(configEntry.getType()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
subcommand.then(argument("value", pair.getValue().first.get())
|
||||||
|
.executes(makeConfigUpdater.apply(c -> pair.getValue().second.apply(c, "value"))));
|
||||||
|
|
||||||
|
setterAdded = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setterAdded)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Config type of "+type.getName()+" is not supported: "+configEntry.getType().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.then(subcommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.commandDispatcher.register(builder);
|
||||||
|
|
||||||
|
if (DEBUG_ENABLE_CODEC_CRASH_MESSAGE)
|
||||||
|
{
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> dhcrash = literal("dhcrash")
|
||||||
|
.requires(source -> source.hasPermission(4))
|
||||||
|
.then(literal("encode")
|
||||||
|
.executes(c -> {
|
||||||
|
assert SharedApi.getIDhServerWorld() != null;
|
||||||
|
((DhServerWorld) SharedApi.getIDhServerWorld()).remotePlayerConnectionHandler
|
||||||
|
#if MC_VER >= MC_1_19_2
|
||||||
|
.getConnectedPlayer(ServerPlayerWrapper.getWrapper(Objects.requireNonNull(c.getSource().getPlayer())))
|
||||||
|
#else
|
||||||
|
.getConnectedPlayer(ServerPlayerWrapper.getWrapper(Objects.requireNonNull(c.getSource().getPlayerOrException())))
|
||||||
|
#endif
|
||||||
|
.session.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.ENCODE));
|
||||||
|
return 1;
|
||||||
|
}))
|
||||||
|
.then(literal("decode")
|
||||||
|
.executes(c -> {
|
||||||
|
assert SharedApi.getIDhServerWorld() != null;
|
||||||
|
((DhServerWorld) SharedApi.getIDhServerWorld()).remotePlayerConnectionHandler
|
||||||
|
#if MC_VER >= MC_1_19_2
|
||||||
|
.getConnectedPlayer(ServerPlayerWrapper.getWrapper(Objects.requireNonNull(c.getSource().getPlayer())))
|
||||||
|
#else
|
||||||
|
.getConnectedPlayer(ServerPlayerWrapper.getWrapper(Objects.requireNonNull(c.getSource().getPlayerOrException())))
|
||||||
|
#endif
|
||||||
|
.session.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.DECODE));
|
||||||
|
return 1;
|
||||||
|
}));
|
||||||
|
this.commandDispatcher.register(dhcrash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+114
@@ -0,0 +1,114 @@
|
|||||||
|
package com.seibel.distanthorizons.common;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||||
|
import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageEvent;
|
||||||
|
import com.seibel.distanthorizons.core.network.event.internal.ProtocolErrorEvent;
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
import io.netty.buffer.ByteBufUtil;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public abstract class AbstractPluginPacketSender implements IPluginPacketSender
|
||||||
|
{
|
||||||
|
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
|
||||||
|
() -> Config.Client.Advanced.Logging.logNetworkEvent.get());
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_21_1
|
||||||
|
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
||||||
|
#else
|
||||||
|
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void sendPluginPacketServer(IServerPlayerWrapper serverPlayer, NetworkMessage message)
|
||||||
|
{
|
||||||
|
this.sendPluginPacketServer((ServerPlayer) serverPlayer.getWrappedMcObject(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract void sendPluginPacketClient(NetworkMessage message);
|
||||||
|
public abstract void sendPluginPacketServer(ServerPlayer serverPlayer, NetworkMessage message);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static NetworkMessage decodeMessage(FriendlyByteBuf in)
|
||||||
|
{
|
||||||
|
NetworkMessage message = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
in.markReaderIndex();
|
||||||
|
|
||||||
|
int protocolVersion = in.readShort();
|
||||||
|
if (protocolVersion != ModInfo.PROTOCOL_VERSION)
|
||||||
|
{
|
||||||
|
return new IncompatibleMessageEvent(protocolVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
message = MessageRegistry.INSTANCE.createMessage(in.readUnsignedShort());
|
||||||
|
message.decode(in);
|
||||||
|
|
||||||
|
if (in.isReadable())
|
||||||
|
{
|
||||||
|
throw new IOException("Buffer has not been fully read");
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
in.resetReaderIndex();
|
||||||
|
|
||||||
|
LOGGER.error("Failed to decode message", e);
|
||||||
|
LOGGER.error("Buffer: {}", in);
|
||||||
|
LOGGER.error("Buffer contents: [{}]", ByteBufUtil.hexDump(in));
|
||||||
|
|
||||||
|
return new ProtocolErrorEvent(e, message, true);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Prevent connection crashing if not entire buffer has been read
|
||||||
|
in.readerIndex(in.writerIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void encodeMessage(FriendlyByteBuf out, NetworkMessage message)
|
||||||
|
{
|
||||||
|
// This is intentionally unhandled, because errors related to this are unlikely to appear in wild
|
||||||
|
Objects.requireNonNull(message);
|
||||||
|
out.writeShort(ModInfo.PROTOCOL_VERSION);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
out.markWriterIndex();
|
||||||
|
out.writeShort(MessageRegistry.INSTANCE.getMessageId(message));
|
||||||
|
message.encode(out);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOGGER.error("Failed to encode message", e);
|
||||||
|
LOGGER.error("Message: {}", message);
|
||||||
|
|
||||||
|
message.getSession().tryHandleMessage(new ProtocolErrorEvent(e, message, false));
|
||||||
|
|
||||||
|
// Encode close reason message instead
|
||||||
|
out.resetWriterIndex();
|
||||||
|
message = new CloseReasonMessage("Internal error on other side");
|
||||||
|
out.writeShort(MessageRegistry.INSTANCE.getMessageId(message));
|
||||||
|
message.encode(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.seibel.distanthorizons.common;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_20_6
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public record CommonPacketPayload(
|
||||||
|
@Nullable NetworkMessage message
|
||||||
|
) implements CustomPacketPayload
|
||||||
|
{
|
||||||
|
public static final Type<CommonPacketPayload> TYPE = new Type<>(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Type<? extends CustomPacketPayload> type()
|
||||||
|
{
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Codec implements StreamCodec<FriendlyByteBuf, CommonPacketPayload>
|
||||||
|
{
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public CommonPacketPayload decode(@NotNull FriendlyByteBuf in)
|
||||||
|
{
|
||||||
|
return new CommonPacketPayload(AbstractPluginPacketSender.decodeMessage(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(@NotNull FriendlyByteBuf out, CommonPacketPayload payload)
|
||||||
|
{
|
||||||
|
AbstractPluginPacketSender.encodeMessage(out, payload.message());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
package com.seibel.distanthorizons.common.commonMixins;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
public class MixinChunkMapCommon
|
||||||
|
{
|
||||||
|
|
||||||
|
public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
|
||||||
|
{
|
||||||
|
// is this position already being updated?
|
||||||
|
if (SharedApi.isChunkAtChunkPosAlreadyUpdating(chunk.getPos().x, chunk.getPos().z))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// is this chunk being saved to disk?
|
||||||
|
boolean savingChunkToDisk = ci.getReturnValue();
|
||||||
|
// true means a chunk was saved to disk
|
||||||
|
if (!savingChunkToDisk)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO are the following validations necessary since we are checking above if
|
||||||
|
// the callback return value should state if the chunk was actually saved or not?
|
||||||
|
// Do we trust it to always be correct?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// corrupt/incomplete chunk validation //
|
||||||
|
|
||||||
|
// MC has a tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks)
|
||||||
|
// this logic should prevent that from happening
|
||||||
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
|
if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// biome validation //
|
||||||
|
|
||||||
|
// some chunks may be missing their biomes, which cause issues when attempting to save them
|
||||||
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
|
if (chunk.getBiomes() == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// this will throw an exception if the biomes aren't set up
|
||||||
|
chunk.getNoiseBiome(0,0,0);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// submit the update event
|
||||||
|
ServerApi.INSTANCE.serverChunkSaveEvent(
|
||||||
|
new ChunkWrapper(chunk, level, ServerLevelWrapper.getWrapper(level)),
|
||||||
|
ServerLevelWrapper.getWrapper(level)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+6
-39
@@ -20,13 +20,11 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers;
|
package com.seibel.distanthorizons.common.wrappers;
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
@@ -137,41 +135,10 @@ public class McObjectConverter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlockPos Convert(DhBlockPos wrappedPos)
|
public static BlockPos Convert(DhBlockPos wrappedPos) { return new BlockPos(wrappedPos.getX(), wrappedPos.getY(), wrappedPos.getZ()); }
|
||||||
{
|
public static ChunkPos Convert(DhChunkPos wrappedPos) { return new ChunkPos(wrappedPos.getX(), wrappedPos.getZ()); }
|
||||||
return new BlockPos(wrappedPos.x, wrappedPos.y, wrappedPos.z);
|
|
||||||
}
|
|
||||||
public static ChunkPos Convert(DhChunkPos wrappedPos)
|
|
||||||
{
|
|
||||||
return new ChunkPos(wrappedPos.x, wrappedPos.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Direction Convert(EDhDirection lodDirection)
|
public static Direction Convert(EDhDirection lodDirection) { return directions[lodDirection.ordinal()]; }
|
||||||
{
|
public static EDhDirection Convert(Direction direction) { return lodDirections[direction.ordinal()]; }
|
||||||
return directions[lodDirection.ordinal()];
|
|
||||||
}
|
|
||||||
public static EDhDirection 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-52
@@ -55,9 +55,6 @@ import java.util.HashSet;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This handles creating abstract wrapper objects.
|
* This handles creating abstract wrapper objects.
|
||||||
*
|
|
||||||
* @author James Seibel
|
|
||||||
* @version 2022-12-5
|
|
||||||
*/
|
*/
|
||||||
public class WrapperFactory implements IWrapperFactory
|
public class WrapperFactory implements IWrapperFactory
|
||||||
{
|
{
|
||||||
@@ -82,6 +79,27 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IDhApiBiomeWrapper getBiomeWrapper(String resourceLocationString, IDhApiLevelWrapper levelWrapper) throws IOException, ClassCastException
|
||||||
|
{
|
||||||
|
if (!(levelWrapper instanceof ILevelWrapper))
|
||||||
|
{
|
||||||
|
throw new ClassCastException("levelWrapper must be returned by DH and of type ["+ILevelWrapper.class.getName()+"].");
|
||||||
|
}
|
||||||
|
|
||||||
|
return BiomeWrapper.deserialize(resourceLocationString, (ILevelWrapper)levelWrapper);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public IDhApiBlockStateWrapper getDefaultBlockStateWrapper(String resourceLocationString, IDhApiLevelWrapper levelWrapper) throws IOException, ClassCastException
|
||||||
|
{
|
||||||
|
if (!(levelWrapper instanceof ILevelWrapper))
|
||||||
|
{
|
||||||
|
throw new ClassCastException("Invalid ["+IDhApiLevelWrapper.class.getSimpleName()+"] value given. Level wrapper object must be one given by the DH API (it can't be a custom implementation), specifically of type ["+ILevelWrapper.class.getName()+"].");
|
||||||
|
}
|
||||||
|
|
||||||
|
return BlockStateWrapper.deserialize(resourceLocationString, (ILevelWrapper)levelWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BiomeWrapper.deserialize(str, levelWrapper); }
|
public IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BiomeWrapper.deserialize(str, levelWrapper); }
|
||||||
@Override
|
@Override
|
||||||
@@ -104,6 +122,13 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredBlocks(levelWrapper); }
|
public HashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredBlocks(levelWrapper); }
|
||||||
|
@Override
|
||||||
|
public HashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredCaveBlocks(levelWrapper); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resetRendererIgnoredCaveBlocks() { BlockStateWrapper.clearRendererIgnoredCaveBlocks(); }
|
||||||
|
@Override
|
||||||
|
public void resetRendererIgnoredBlocksSet() { BlockStateWrapper.clearRendererIgnoredBlocks(); }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,7 +155,7 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MC_VER <= MC_1_20_6
|
//#if MC_VER <= MC_1_XX_X
|
||||||
else if (objectArray.length == 2)
|
else if (objectArray.length == 2)
|
||||||
{
|
{
|
||||||
// correct number of parameters from the API
|
// correct number of parameters from the API
|
||||||
@@ -154,19 +179,9 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
|
|
||||||
|
|
||||||
// level wrapper
|
// level wrapper
|
||||||
ILevelWrapper levelWrapper;
|
ILevelWrapper levelWrapper = level.isClientSide()
|
||||||
if (level instanceof ServerLevel)
|
? ClientLevelWrapper.getWrapper((ClientLevel)level)
|
||||||
{
|
: ServerLevelWrapper.getWrapper((ServerLevel)level);
|
||||||
levelWrapper = ServerLevelWrapper.getWrapper((ServerLevel)level);
|
|
||||||
}
|
|
||||||
else if (level instanceof ClientLevel)
|
|
||||||
{
|
|
||||||
levelWrapper = ClientLevelWrapper.getWrapper((ClientLevel)level);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return new ChunkWrapper(chunk, lightSource, levelWrapper);
|
return new ChunkWrapper(chunk, lightSource, levelWrapper);
|
||||||
@@ -176,16 +191,7 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
{
|
{
|
||||||
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
|
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
|
||||||
}
|
}
|
||||||
#else
|
//#endif
|
||||||
// Intentional compiler error to bring attention to the missing wrapper function.
|
|
||||||
// If you need to work on an unimplemented version but don't have the ability to implement this yet
|
|
||||||
// you can comment it out, but please don't commit it. Someone will have to implement it.
|
|
||||||
|
|
||||||
// After implementing the new version please read this method's javadocs for instructions
|
|
||||||
// on what other locations also need to be updated, the DhAPI specifically needs to
|
|
||||||
// be updated to state which objects this method accepts.
|
|
||||||
not implemented for this version of Minecraft!
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Note: when this is updated for different MC versions,
|
* Note: when this is updated for different MC versions,
|
||||||
@@ -195,16 +201,13 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
{
|
{
|
||||||
String[] expectedClassNames;
|
String[] expectedClassNames;
|
||||||
|
|
||||||
#if MC_VER <= MC_1_20_6
|
//#if MC_VER <= MC_1_XX_X
|
||||||
expectedClassNames = new String[]
|
expectedClassNames = new String[]
|
||||||
{
|
{
|
||||||
ChunkAccess.class.getName(),
|
ChunkAccess.class.getName(),
|
||||||
ServerLevel.class.getName() + "] or [" + ClientLevel.class.getName()
|
"[ServerLevel] or [ClientLevel]" // Classes are not referenced by names to avoid exception when one of them is missing
|
||||||
};
|
};
|
||||||
#else
|
//#endif
|
||||||
// See preprocessor comment in createChunkWrapper() for full documentation
|
|
||||||
not implemented for this version of Minecraft!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return createWrapperErrorMessage("Chunk wrapper", expectedClassNames, objectArray);
|
return createWrapperErrorMessage("Chunk wrapper", expectedClassNames, objectArray);
|
||||||
}
|
}
|
||||||
@@ -222,7 +225,7 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
// confirm the API level wrapper is also a Core wrapper
|
// confirm the API level wrapper is also a Core wrapper
|
||||||
if (!(levelWrapper instanceof ILevelWrapper))
|
if (!(levelWrapper instanceof ILevelWrapper))
|
||||||
{
|
{
|
||||||
throw new ClassCastException("Unable to cast... only DH provided IDhApiLevelWrapper's can be used."); // TODO
|
throw new ClassCastException("Invalid ["+IDhApiLevelWrapper.class.getSimpleName()+"] value given. Level wrapper object must be one given by the DH API (it can't be a custom implementation), specifically of type ["+ILevelWrapper.class.getName()+"].");
|
||||||
}
|
}
|
||||||
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
|
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
|
||||||
|
|
||||||
@@ -243,7 +246,7 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
|
|
||||||
Biome biome = (Biome) objectArray[0];
|
Biome biome = (Biome) objectArray[0];
|
||||||
return BiomeWrapper.getBiomeWrapper(biome, coreLevelWrapper);
|
return BiomeWrapper.getBiomeWrapper(biome, coreLevelWrapper);
|
||||||
#elif MC_VER <= MC_1_20_6
|
#else
|
||||||
if (!(objectArray[0] instanceof Holder) || !(((Holder<?>) objectArray[0]).value() instanceof Biome))
|
if (!(objectArray[0] instanceof Holder) || !(((Holder<?>) objectArray[0]).value() instanceof Biome))
|
||||||
{
|
{
|
||||||
throw new ClassCastException(createBiomeWrapperErrorMessage(objectArray));
|
throw new ClassCastException(createBiomeWrapperErrorMessage(objectArray));
|
||||||
@@ -251,9 +254,6 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
|
|
||||||
Holder<Biome> biomeHolder = (Holder<Biome>) objectArray[0];
|
Holder<Biome> biomeHolder = (Holder<Biome>) objectArray[0];
|
||||||
return BiomeWrapper.getBiomeWrapper(biomeHolder, coreLevelWrapper);
|
return BiomeWrapper.getBiomeWrapper(biomeHolder, coreLevelWrapper);
|
||||||
#else
|
|
||||||
// See preprocessor comment in createChunkWrapper() for full documentation (not a typo, check createChunkWrapper()'s else statement for full documentation)
|
|
||||||
not implemented for this version of Minecraft!
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -266,11 +266,8 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
|
|
||||||
#if MC_VER < MC_1_18_2
|
#if MC_VER < MC_1_18_2
|
||||||
expectedClassNames = new String[] { Biome.class.getName() };
|
expectedClassNames = new String[] { Biome.class.getName() };
|
||||||
#elif MC_VER <= MC_1_20_6
|
|
||||||
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
|
|
||||||
#else
|
#else
|
||||||
// See preprocessor comment in createChunkWrapper() for full documentation
|
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
|
||||||
not implemented for this version of Minecraft!
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return createWrapperErrorMessage("Biome wrapper", expectedClassNames, objectArray);
|
return createWrapperErrorMessage("Biome wrapper", expectedClassNames, objectArray);
|
||||||
@@ -281,13 +278,13 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
// confirm the API level wrapper is also a Core wrapper
|
// confirm the API level wrapper is also a Core wrapper
|
||||||
if (!(levelWrapper instanceof ILevelWrapper))
|
if (!(levelWrapper instanceof ILevelWrapper))
|
||||||
{
|
{
|
||||||
throw new ClassCastException("Unable to cast... only DH provided IDhApiLevelWrapper's can be used."); // TODO
|
throw new ClassCastException("Invalid ["+IDhApiLevelWrapper.class.getSimpleName()+"] value given. Level wrapper object must be one given by the DH API (it can't be a custom implementation), specifically of type ["+ILevelWrapper.class.getName()+"].");
|
||||||
}
|
}
|
||||||
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
|
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER <= MC_1_20_6
|
//#if MC_VER <= MC_1_XX_X
|
||||||
if (objectArray.length != 1)
|
if (objectArray.length != 1)
|
||||||
{
|
{
|
||||||
throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray));
|
throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray));
|
||||||
@@ -299,10 +296,7 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
|
|
||||||
BlockState blockState = (BlockState) objectArray[0];
|
BlockState blockState = (BlockState) objectArray[0];
|
||||||
return BlockStateWrapper.fromBlockState(blockState, coreLevelWrapper);
|
return BlockStateWrapper.fromBlockState(blockState, coreLevelWrapper);
|
||||||
#else
|
//#endif
|
||||||
// See preprocessor comment in createChunkWrapper() for full documentation (not a typo, check createChunkWrapper()'s else statement for full documentation)
|
|
||||||
not implemented for this version of Minecraft!
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Note: when this is updated for different MC versions,
|
* Note: when this is updated for different MC versions,
|
||||||
@@ -314,11 +308,8 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
expectedClassNames = new String[] { Biome.class.getName() };
|
expectedClassNames = new String[] { Biome.class.getName() };
|
||||||
#elif MC_VER <= MC_1_20_6
|
|
||||||
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
|
|
||||||
#else
|
#else
|
||||||
// See preprocessor comment in createChunkWrapper() for full documentation
|
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
|
||||||
not implemented for this version of Minecraft!
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return createWrapperErrorMessage("BlockState wrapper", expectedClassNames, objectArray);
|
return createWrapperErrorMessage("BlockState wrapper", expectedClassNames, objectArray);
|
||||||
|
|||||||
+4
@@ -293,7 +293,11 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
ResourceLocation resourceLocation;
|
ResourceLocation resourceLocation;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
||||||
|
#else
|
||||||
|
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
+193
-48
@@ -19,20 +19,28 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.block;
|
package com.seibel.distanthorizons.common.wrappers.block;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.tags.BlockTags;
|
import net.minecraft.tags.BlockTags;
|
||||||
|
import net.minecraft.world.level.block.BeaconBeamBlock;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.SoundType;
|
import net.minecraft.world.level.block.SoundType;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
@@ -46,7 +54,6 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.world.level.EmptyBlockGetter;
|
import net.minecraft.world.level.EmptyBlockGetter;
|
||||||
#else
|
#else
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
@@ -72,9 +79,8 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
|
|
||||||
public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt";
|
public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt";
|
||||||
|
|
||||||
// TODO: Make this changeable through the config
|
|
||||||
public static final String[] RENDERER_IGNORED_BLOCKS_RESOURCE_LOCATIONS = { AIR_STRING, "minecraft:barrier", "minecraft:structure_void", "minecraft:light", "minecraft:tripwire" };
|
|
||||||
public static HashSet<IBlockStateWrapper> rendererIgnoredBlocks = null;
|
public static HashSet<IBlockStateWrapper> rendererIgnoredBlocks = null;
|
||||||
|
public static HashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null;
|
||||||
|
|
||||||
/** keep track of broken blocks so we don't log every time */
|
/** keep track of broken blocks so we don't log every time */
|
||||||
private static final HashSet<ResourceLocation> BrokenResourceLocations = new HashSet<>();
|
private static final HashSet<ResourceLocation> BrokenResourceLocations = new HashSet<>();
|
||||||
@@ -89,11 +95,17 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
private final int hashCode;
|
private final int hashCode;
|
||||||
/**
|
/**
|
||||||
* Cached opacity value, -1 if not populated. <br>
|
* Cached opacity value, -1 if not populated. <br>
|
||||||
* Should be between {@link IBlockStateWrapper#FULLY_OPAQUE} and {@link IBlockStateWrapper#FULLY_OPAQUE}
|
* Should be between {@link LodUtil#BLOCK_FULLY_OPAQUE} and {@link LodUtil#BLOCK_FULLY_OPAQUE}
|
||||||
*/
|
*/
|
||||||
private int opacity = -1;
|
private int opacity = -1;
|
||||||
/** used by the Iris shader mod to determine how each LOD should be rendered */
|
/** used by the Iris shader mod to determine how each LOD should be rendered */
|
||||||
private byte irisBlockMaterialId = 0;
|
private byte blockMaterialId = 0;
|
||||||
|
|
||||||
|
private final boolean isBeaconBlock;
|
||||||
|
private final boolean isBeaconBaseBlock;
|
||||||
|
/** null if this block can't tint beacons */
|
||||||
|
private final Color beaconTintColor;
|
||||||
|
private final Color mapColor;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -126,16 +138,68 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
this.blockState = blockState;
|
this.blockState = blockState;
|
||||||
this.serialString = this.serialize(levelWrapper);
|
this.serialString = this.serialize(levelWrapper);
|
||||||
this.hashCode = Objects.hash(this.serialString);
|
this.hashCode = Objects.hash(this.serialString);
|
||||||
this.irisBlockMaterialId = this.calculateIrisBlockMaterialId();
|
this.blockMaterialId = this.calculateEDhApiBlockMaterialId().index;
|
||||||
|
|
||||||
//LOGGER.trace("Created BlockStateWrapper ["+this.serialString+"] for ["+blockState+"] with material ID ["+this.irisBlockMaterialId+"]");
|
// beacon blocks
|
||||||
|
String lowercaseSerial = this.serialString.toLowerCase();
|
||||||
|
boolean isBeaconBaseBlock = false;
|
||||||
|
for (int i = 0; i < LodUtil.BEACON_BASE_BLOCK_NAME_LIST.size(); i++)
|
||||||
|
{
|
||||||
|
String baseBlockName = LodUtil.BEACON_BASE_BLOCK_NAME_LIST.get(i);
|
||||||
|
if (lowercaseSerial.contains(baseBlockName))
|
||||||
|
{
|
||||||
|
isBeaconBaseBlock = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.isBeaconBaseBlock = isBeaconBaseBlock;
|
||||||
|
this.isBeaconBlock = lowercaseSerial.contains("minecraft:beacon");
|
||||||
|
|
||||||
|
// beacon tint color
|
||||||
|
Color beaconTintColor = null;
|
||||||
|
if (this.blockState != null
|
||||||
|
// beacon blocks also show up here, but since they block the beacon beam we don't want their color
|
||||||
|
&& !this.isBeaconBlock)
|
||||||
|
{
|
||||||
|
Block block = this.blockState.getBlock();
|
||||||
|
if (block instanceof BeaconBeamBlock)
|
||||||
|
{
|
||||||
|
int colorInt;
|
||||||
|
#if MC_VER <= MC_1_19_4
|
||||||
|
colorInt = ((BeaconBeamBlock) block).getColor().getMaterialColor().col;
|
||||||
|
#else
|
||||||
|
colorInt = ((BeaconBeamBlock) block).getColor().getMapColor().col;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
beaconTintColor = ColorUtil.toColorObjRGB(colorInt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.beaconTintColor = beaconTintColor;
|
||||||
|
|
||||||
|
|
||||||
|
int mcColor = 0;
|
||||||
|
if (this.blockState != null)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_20_1
|
||||||
|
mcColor = this.blockState.getMaterial().getColor().col;
|
||||||
|
#else
|
||||||
|
mcColor = this.blockState.getMapColor(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).col;
|
||||||
|
#endif
|
||||||
|
this.mapColor = ColorUtil.toColorObjRGB(mcColor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.mapColor = new Color(0,0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//LOGGER.trace("Created BlockStateWrapper ["+this.serialString+"] for ["+blockState+"] with material ID ["+this.EDhApiBlockMaterialId+"]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
//====================//
|
||||||
// helper methods //
|
// LodBuilder methods //
|
||||||
//================//
|
//====================//
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requires a {@link ILevelWrapper} since {@link BlockStateWrapper#deserialize(String,ILevelWrapper)} also requires one.
|
* Requires a {@link ILevelWrapper} since {@link BlockStateWrapper#deserialize(String,ILevelWrapper)} also requires one.
|
||||||
@@ -149,37 +213,104 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
return rendererIgnoredBlocks;
|
return rendererIgnoredBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashSet<String> baseIgnoredBlock = new HashSet<>();
|
||||||
|
baseIgnoredBlock.add(AIR_STRING);
|
||||||
|
rendererIgnoredBlocks = getBlockWrappers(Config.Client.Advanced.LodBuilding.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper);
|
||||||
|
return rendererIgnoredBlocks;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Requires a {@link ILevelWrapper} since {@link BlockStateWrapper#deserialize(String,ILevelWrapper)} also requires one.
|
||||||
|
* This way the method won't accidentally be called before the deserialization can be completed.
|
||||||
|
*/
|
||||||
|
public static HashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper)
|
||||||
|
{
|
||||||
|
// use the cached version if possible
|
||||||
|
if (rendererIgnoredCaveBlocks != null)
|
||||||
|
{
|
||||||
|
return rendererIgnoredCaveBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashSet<String> baseIgnoredBlock = new HashSet<>();
|
||||||
|
baseIgnoredBlock.add(AIR_STRING);
|
||||||
|
rendererIgnoredCaveBlocks = getBlockWrappers(Config.Client.Advanced.LodBuilding.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper);
|
||||||
|
return rendererIgnoredCaveBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearRendererIgnoredBlocks() { rendererIgnoredBlocks = null; }
|
||||||
|
public static void clearRendererIgnoredCaveBlocks() { rendererIgnoredCaveBlocks = null; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// lod builder helpers //
|
||||||
|
|
||||||
|
private static HashSet<IBlockStateWrapper> getBlockWrappers(ConfigEntry<String> config, HashSet<String> baseResourceLocations, ILevelWrapper levelWrapper)
|
||||||
|
{
|
||||||
|
// get the base blocks
|
||||||
|
HashSet<String> blockStringList = new HashSet<>();
|
||||||
|
if (baseResourceLocations != null)
|
||||||
|
{
|
||||||
|
blockStringList.addAll(baseResourceLocations);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the config blocks
|
||||||
|
String ignoreBlockCsv = config.get();
|
||||||
|
if (ignoreBlockCsv != null)
|
||||||
|
{
|
||||||
|
blockStringList.addAll(Arrays.asList(ignoreBlockCsv.split(",")));
|
||||||
|
}
|
||||||
|
|
||||||
|
return getBlockWrappers(blockStringList, levelWrapper);
|
||||||
|
}
|
||||||
|
private static HashSet<IBlockStateWrapper> getBlockWrappers(HashSet<String> blockResourceLocationSet, ILevelWrapper levelWrapper)
|
||||||
|
{
|
||||||
// deserialize each of the given resource locations
|
// deserialize each of the given resource locations
|
||||||
HashSet<IBlockStateWrapper> blockStateWrappers = new HashSet<>();
|
HashSet<IBlockStateWrapper> blockStateWrappers = new HashSet<>();
|
||||||
for (String blockResourceLocation : RENDERER_IGNORED_BLOCKS_RESOURCE_LOCATIONS)
|
for (String blockResourceLocation : blockResourceLocationSet)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
BlockStateWrapper DefaultBlockStateToIgnore = (BlockStateWrapper) deserialize(blockResourceLocation, levelWrapper);
|
if (blockResourceLocation == null)
|
||||||
blockStateWrappers.add(DefaultBlockStateToIgnore);
|
{
|
||||||
|
// shouldn't happen, but just in case
|
||||||
if (DefaultBlockStateToIgnore == AIR)
|
continue;
|
||||||
|
}
|
||||||
|
String cleanedResourceLocation = blockResourceLocation.trim();
|
||||||
|
if (cleanedResourceLocation.length() == 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add all possible blockstates (to account for light blocks with different light values and such)
|
|
||||||
List<BlockState> blockStatesToIgnore = DefaultBlockStateToIgnore.blockState.getBlock().getStateDefinition().getPossibleStates();
|
BlockStateWrapper defaultBlockStateToIgnore = (BlockStateWrapper) deserialize(cleanedResourceLocation, levelWrapper);
|
||||||
for (BlockState blockState : blockStatesToIgnore)
|
blockStateWrappers.add(defaultBlockStateToIgnore);
|
||||||
|
|
||||||
|
if (defaultBlockStateToIgnore != AIR)
|
||||||
{
|
{
|
||||||
BlockStateWrapper newBlockToIgnore = BlockStateWrapper.fromBlockState(blockState, levelWrapper);
|
// add all possible blockstates (to account for light blocks with different light values and such)
|
||||||
blockStateWrappers.add(newBlockToIgnore);
|
List<BlockState> blockStatesToIgnore = defaultBlockStateToIgnore.blockState.getBlock().getStateDefinition().getPossibleStates();
|
||||||
|
for (BlockState blockState : blockStatesToIgnore)
|
||||||
|
{
|
||||||
|
BlockStateWrapper newBlockToIgnore = BlockStateWrapper.fromBlockState(blockState, levelWrapper);
|
||||||
|
blockStateWrappers.add(newBlockToIgnore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// air is a special case so it must be handled separately
|
||||||
|
blockStateWrappers.add(AIR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
LOGGER.warn("Unable to deserialize rendererIgnoredBlock with the resource location: ["+blockResourceLocation+"]. Error: "+e.getMessage(), e);
|
LOGGER.warn("Unable to deserialize block with the resource location: ["+blockResourceLocation+"]. Error: "+e.getMessage(), e);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Unexpected error deserializing block with the resource location: ["+blockResourceLocation+"]. Error: "+e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rendererIgnoredBlocks = blockStateWrappers;
|
return blockStateWrappers;
|
||||||
return rendererIgnoredBlocks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -202,23 +333,23 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
int opacity;
|
int opacity;
|
||||||
if (this.isAir())
|
if (this.isAir())
|
||||||
{
|
{
|
||||||
opacity = FULLY_TRANSPARENT;
|
opacity = LodUtil.BLOCK_FULLY_TRANSPARENT;
|
||||||
}
|
}
|
||||||
else if (this.isLiquid() && !this.blockState.canOcclude())
|
else if (this.isLiquid() && !this.blockState.canOcclude())
|
||||||
{
|
{
|
||||||
// probably not a waterlogged block (which should block light entirely)
|
// probably not a waterlogged block (which should block light entirely)
|
||||||
|
|
||||||
// +1 to indicate that the block is translucent (in between transparent and opaque)
|
// +1 to indicate that the block is translucent (in between transparent and opaque)
|
||||||
opacity = FULLY_TRANSPARENT + 1;
|
opacity = LodUtil.BLOCK_FULLY_TRANSPARENT + 1;
|
||||||
}
|
}
|
||||||
else if (this.blockState.propagatesSkylightDown(EmptyBlockGetter.INSTANCE, BlockPos.ZERO))
|
else if (this.blockState.propagatesSkylightDown(EmptyBlockGetter.INSTANCE, BlockPos.ZERO))
|
||||||
{
|
{
|
||||||
opacity = FULLY_TRANSPARENT;
|
opacity = LodUtil.BLOCK_FULLY_TRANSPARENT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// default for all other blocks
|
// default for all other blocks
|
||||||
opacity = FULLY_OPAQUE;
|
opacity = LodUtil.BLOCK_FULLY_OPAQUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -287,7 +418,19 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte getIrisBlockMaterialId() { return this.irisBlockMaterialId; }
|
public boolean isBeaconBlock() { return this.isBeaconBlock; }
|
||||||
|
@Override
|
||||||
|
public boolean isBeaconBaseBlock() { return this.isBeaconBaseBlock; }
|
||||||
|
@Override
|
||||||
|
public boolean isBeaconTintBlock() { return this.beaconTintColor != null; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Color getMapColor() { return this.mapColor; }
|
||||||
|
@Override
|
||||||
|
public Color getBeaconTintColor() { return this.beaconTintColor; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getMaterialId() { return this.blockMaterialId; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() { return this.getSerialString(); }
|
public String toString() { return this.getSerialString(); }
|
||||||
@@ -380,7 +523,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
ResourceLocation resourceLocation;
|
ResourceLocation resourceLocation;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
resourceLocation = new ResourceLocation(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
resourceLocation = new ResourceLocation(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
||||||
|
#else
|
||||||
|
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -394,9 +541,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
{
|
{
|
||||||
|
|
||||||
#if MC_VER > MC_1_17_1
|
#if MC_VER > MC_1_17_1
|
||||||
// use the given level if possible, otherwise try using the currently loaded one
|
Level level = (Level)Objects.requireNonNull(levelWrapper.getWrappedMcObject());
|
||||||
Level level = (levelWrapper != null ? (Level) levelWrapper.getWrappedMcObject() : null);
|
|
||||||
level = (level == null ? Minecraft.getInstance().level : level);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Block block;
|
Block block;
|
||||||
@@ -508,11 +653,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
// Iris methods //
|
// Iris methods //
|
||||||
//==============//
|
//==============//
|
||||||
|
|
||||||
private byte calculateIrisBlockMaterialId()
|
private EDhApiBlockMaterial calculateEDhApiBlockMaterialId()
|
||||||
{
|
{
|
||||||
if (this.blockState == null)
|
if (this.blockState == null)
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.AIR;
|
return EDhApiBlockMaterial.AIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -525,15 +670,15 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
|| serialString.contains("mushroom")
|
|| serialString.contains("mushroom")
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.LEAVES;
|
return EDhApiBlockMaterial.LEAVES;
|
||||||
}
|
}
|
||||||
else if (this.blockState.is(Blocks.LAVA))
|
else if (this.blockState.is(Blocks.LAVA))
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.LAVA;
|
return EDhApiBlockMaterial.LAVA;
|
||||||
}
|
}
|
||||||
else if (this.isLiquid() || this.blockState.is(Blocks.WATER))
|
else if (this.isLiquid() || this.blockState.is(Blocks.WATER))
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.WATER;
|
return EDhApiBlockMaterial.WATER;
|
||||||
}
|
}
|
||||||
else if (this.blockState.getSoundType() == SoundType.WOOD
|
else if (this.blockState.getSoundType() == SoundType.WOOD
|
||||||
|| serialString.contains("root")
|
|| serialString.contains("root")
|
||||||
@@ -542,7 +687,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.WOOD;
|
return EDhApiBlockMaterial.WOOD;
|
||||||
}
|
}
|
||||||
else if (this.blockState.getSoundType() == SoundType.METAL
|
else if (this.blockState.getSoundType() == SoundType.METAL
|
||||||
#if MC_VER >= MC_1_19_2
|
#if MC_VER >= MC_1_19_2
|
||||||
@@ -554,11 +699,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.METAL;
|
return EDhApiBlockMaterial.METAL;
|
||||||
}
|
}
|
||||||
else if (serialString.contains("grass_block"))
|
else if (serialString.contains("grass_block"))
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.GRASS;
|
return EDhApiBlockMaterial.GRASS;
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
serialString.contains("dirt")
|
serialString.contains("dirt")
|
||||||
@@ -568,7 +713,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
|| serialString.contains("mycelium")
|
|| serialString.contains("mycelium")
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.DIRT;
|
return EDhApiBlockMaterial.DIRT;
|
||||||
}
|
}
|
||||||
#if MC_VER >= MC_1_17_1
|
#if MC_VER >= MC_1_17_1
|
||||||
else if (this.blockState.getSoundType() == SoundType.DEEPSLATE
|
else if (this.blockState.getSoundType() == SoundType.DEEPSLATE
|
||||||
@@ -577,37 +722,37 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
|| this.blockState.getSoundType() == SoundType.POLISHED_DEEPSLATE
|
|| this.blockState.getSoundType() == SoundType.POLISHED_DEEPSLATE
|
||||||
|| serialString.contains("deepslate") )
|
|| serialString.contains("deepslate") )
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.DEEPSLATE;
|
return EDhApiBlockMaterial.DEEPSLATE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (this.serialString.contains("snow"))
|
else if (this.serialString.contains("snow"))
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.SNOW;
|
return EDhApiBlockMaterial.SNOW;
|
||||||
}
|
}
|
||||||
else if (serialString.contains("sand"))
|
else if (serialString.contains("sand"))
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.SAND;
|
return EDhApiBlockMaterial.SAND;
|
||||||
}
|
}
|
||||||
else if (serialString.contains("terracotta"))
|
else if (serialString.contains("terracotta"))
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.TERRACOTTA;
|
return EDhApiBlockMaterial.TERRACOTTA;
|
||||||
}
|
}
|
||||||
else if (this.blockState.is(BlockTags.BASE_STONE_NETHER))
|
else if (this.blockState.is(BlockTags.BASE_STONE_NETHER))
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.NETHER_STONE;
|
return EDhApiBlockMaterial.NETHER_STONE;
|
||||||
}
|
}
|
||||||
else if (serialString.contains("stone")
|
else if (serialString.contains("stone")
|
||||||
|| serialString.contains("ore"))
|
|| serialString.contains("ore"))
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.STONE;
|
return EDhApiBlockMaterial.STONE;
|
||||||
}
|
}
|
||||||
else if (this.blockState.getLightEmission() > 0)
|
else if (this.blockState.getLightEmission() > 0)
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.ILLUMINATED;
|
return EDhApiBlockMaterial.ILLUMINATED;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.UNKOWN;
|
return EDhApiBlockMaterial.UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+485
@@ -0,0 +1,485 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020-2023 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.wrappers.block;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||||
|
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||||
|
import com.seibel.distanthorizons.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.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 MC_VER >= MC_1_19_2
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
#else
|
||||||
|
import java.util.Random;
|
||||||
|
#endif
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This stores and calculates the colors
|
||||||
|
* the given {@link BlockState} should have based
|
||||||
|
* on the given {@link IClientLevelWrapper}.
|
||||||
|
*
|
||||||
|
* @see ColorUtil
|
||||||
|
*/
|
||||||
|
public class ClientBlockStateColorCache
|
||||||
|
{
|
||||||
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||||
|
|
||||||
|
private static final HashSet<BlockState> BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>();
|
||||||
|
private static final HashSet<BlockState> BROKEN_BLOCK_STATES = new HashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methods using MC's "RandomSource" object aren't thread safe <br>
|
||||||
|
* so we need to put locks around that logic. <br>
|
||||||
|
* specifically:
|
||||||
|
* <code>
|
||||||
|
* getBlockModel(this.blockState).getQuads(this.blockState, direction, RANDOM)
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
private static final ReentrantLock RESOLVE_LOCK = new ReentrantLock();
|
||||||
|
|
||||||
|
|
||||||
|
/** This is the order each direction on a block is processed when attempting to get the texture/color */
|
||||||
|
private static final Direction[] COLOR_RESOLUTION_DIRECTION_ORDER = { Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN };
|
||||||
|
|
||||||
|
private static final int FLOWER_COLOR_SCALE = 5;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_19_2
|
||||||
|
private static final Random RANDOM = new Random(0);
|
||||||
|
#else
|
||||||
|
/** Note: this object isn't thread safe and must be put in a lock */
|
||||||
|
private static final RandomSource RANDOM = RandomSource.create();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private final IClientLevelWrapper levelWrapper;
|
||||||
|
private final BlockState blockState;
|
||||||
|
private final LevelReader level;
|
||||||
|
|
||||||
|
private boolean isColorResolved = false;
|
||||||
|
private int baseColor = 0;
|
||||||
|
private boolean needShade = true;
|
||||||
|
private boolean needPostTinting = false;
|
||||||
|
private int tintIndex = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// constants //
|
||||||
|
//===========//
|
||||||
|
|
||||||
|
private static final int MIN_SRGB_BITS = 0x39000000; // 2^(-13)
|
||||||
|
private static final int MAX_SRGB_BITS = 0x3f7fffff; // 1.0 - f32::EPSILON
|
||||||
|
private static final float MIN_SRGB_BOUND = Float.intBitsToFloat(MIN_SRGB_BITS);
|
||||||
|
private static final float MAX_SRGB_BOUND = Float.intBitsToFloat(MAX_SRGB_BITS);
|
||||||
|
|
||||||
|
private static final int[] linearToSrgbTable = new int[]
|
||||||
|
{
|
||||||
|
0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
|
||||||
|
0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
|
||||||
|
0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
|
||||||
|
0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
|
||||||
|
0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
|
||||||
|
0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
|
||||||
|
0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
|
||||||
|
0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
|
||||||
|
0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
|
||||||
|
0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
|
||||||
|
0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
|
||||||
|
0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
|
||||||
|
0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final float[] srgbToLinearTable = new float[]
|
||||||
|
{
|
||||||
|
0.0f, 0.000303527f, 0.000607054f, 0.00091058103f, 0.001214108f, 0.001517635f, 0.0018211621f, 0.002124689f,
|
||||||
|
0.002428216f, 0.002731743f, 0.00303527f, 0.0033465356f, 0.003676507f, 0.004024717f, 0.004391442f,
|
||||||
|
0.0047769533f, 0.005181517f, 0.0056053917f, 0.0060488326f, 0.006512091f, 0.00699541f, 0.0074990317f,
|
||||||
|
0.008023192f, 0.008568125f, 0.009134057f, 0.009721218f, 0.010329823f, 0.010960094f, 0.011612245f,
|
||||||
|
0.012286487f, 0.012983031f, 0.013702081f, 0.014443844f, 0.015208514f, 0.015996292f, 0.016807375f,
|
||||||
|
0.017641952f, 0.018500218f, 0.019382361f, 0.020288562f, 0.02121901f, 0.022173883f, 0.023153365f,
|
||||||
|
0.02415763f, 0.025186857f, 0.026241222f, 0.027320892f, 0.028426038f, 0.029556843f, 0.03071345f, 0.03189604f,
|
||||||
|
0.033104774f, 0.03433981f, 0.035601325f, 0.036889452f, 0.038204376f, 0.039546248f, 0.04091521f, 0.042311423f,
|
||||||
|
0.043735042f, 0.045186214f, 0.046665095f, 0.048171833f, 0.049706575f, 0.051269468f, 0.052860655f, 0.05448028f,
|
||||||
|
0.056128494f, 0.057805434f, 0.05951124f, 0.06124607f, 0.06301003f, 0.06480328f, 0.06662595f, 0.06847818f,
|
||||||
|
0.07036011f, 0.07227186f, 0.07421358f, 0.07618539f, 0.07818743f, 0.08021983f, 0.082282715f, 0.084376216f,
|
||||||
|
0.086500466f, 0.088655606f, 0.09084173f, 0.09305898f, 0.095307484f, 0.09758736f, 0.09989874f, 0.10224175f,
|
||||||
|
0.10461649f, 0.10702311f, 0.10946172f, 0.111932434f, 0.11443538f, 0.116970696f, 0.11953845f, 0.12213881f,
|
||||||
|
0.12477186f, 0.12743773f, 0.13013652f, 0.13286836f, 0.13563336f, 0.13843165f, 0.14126332f, 0.1441285f,
|
||||||
|
0.1470273f, 0.14995982f, 0.15292618f, 0.1559265f, 0.15896086f, 0.16202943f, 0.16513224f, 0.16826946f,
|
||||||
|
0.17144115f, 0.17464745f, 0.17788847f, 0.1811643f, 0.18447503f, 0.1878208f, 0.19120172f, 0.19461787f,
|
||||||
|
0.19806935f, 0.2015563f, 0.20507877f, 0.2086369f, 0.21223079f, 0.21586053f, 0.21952623f, 0.22322798f,
|
||||||
|
0.22696589f, 0.23074007f, 0.23455065f, 0.23839766f, 0.2422812f, 0.2462014f, 0.25015837f, 0.25415218f,
|
||||||
|
0.2581829f, 0.26225072f, 0.26635566f, 0.27049786f, 0.27467737f, 0.27889434f, 0.2831488f, 0.2874409f,
|
||||||
|
0.2917707f, 0.29613832f, 0.30054384f, 0.30498737f, 0.30946895f, 0.31398875f, 0.31854683f, 0.32314324f,
|
||||||
|
0.32777813f, 0.33245158f, 0.33716366f, 0.34191445f, 0.3467041f, 0.3515327f, 0.35640025f, 0.36130688f,
|
||||||
|
0.3662527f, 0.37123778f, 0.37626222f, 0.3813261f, 0.38642952f, 0.39157256f, 0.3967553f, 0.40197787f,
|
||||||
|
0.4072403f, 0.4125427f, 0.41788515f, 0.42326775f, 0.42869055f, 0.4341537f, 0.43965724f, 0.44520125f,
|
||||||
|
0.45078585f, 0.45641106f, 0.46207705f, 0.46778384f, 0.47353154f, 0.47932023f, 0.48514998f, 0.4910209f,
|
||||||
|
0.49693304f, 0.5028866f, 0.50888145f, 0.5149178f, 0.5209957f, 0.52711535f, 0.5332766f, 0.5394797f,
|
||||||
|
0.5457247f, 0.5520116f, 0.5583406f, 0.5647117f, 0.57112503f, 0.57758063f, 0.5840786f, 0.590619f, 0.597202f,
|
||||||
|
0.60382754f, 0.61049575f, 0.61720675f, 0.62396055f, 0.63075733f, 0.637597f, 0.6444799f, 0.6514058f,
|
||||||
|
0.65837497f, 0.66538745f, 0.67244333f, 0.6795426f, 0.68668544f, 0.69387203f, 0.70110214f, 0.70837605f,
|
||||||
|
0.7156938f, 0.72305536f, 0.730461f, 0.7379107f, 0.7454045f, 0.75294244f, 0.76052475f, 0.7681514f, 0.77582246f,
|
||||||
|
0.78353804f, 0.79129815f, 0.79910296f, 0.8069525f, 0.8148468f, 0.822786f, 0.8307701f, 0.83879924f, 0.84687346f,
|
||||||
|
0.8549928f, 0.8631574f, 0.87136734f, 0.8796226f, 0.8879232f, 0.89626956f, 0.90466136f, 0.913099f, 0.92158204f,
|
||||||
|
0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper samplingLevel)
|
||||||
|
{
|
||||||
|
this.blockState = blockState;
|
||||||
|
this.levelWrapper = samplingLevel;
|
||||||
|
this.level = (LevelReader) samplingLevel.getWrappedMcObject();
|
||||||
|
this.resolveColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===================//
|
||||||
|
// color calculation //
|
||||||
|
//===================//
|
||||||
|
|
||||||
|
private void resolveColors()
|
||||||
|
{
|
||||||
|
if (this.isColorResolved)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// getQuads() isn't thread safe so we need to put this logic in a lock
|
||||||
|
RESOLVE_LOCK.lock();
|
||||||
|
|
||||||
|
if (this.blockState.getFluidState().isEmpty())
|
||||||
|
{
|
||||||
|
// look for the first non-empty direction
|
||||||
|
List<BakedQuad> quads = null;
|
||||||
|
for (Direction direction : COLOR_RESOLUTION_DIRECTION_ORDER)
|
||||||
|
{
|
||||||
|
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
||||||
|
getBlockModel(this.blockState).getQuads(this.blockState, direction, RANDOM);
|
||||||
|
|
||||||
|
if (quads != null && !quads.isEmpty()
|
||||||
|
&& !(
|
||||||
|
this.blockState.getBlock() instanceof RotatedPillarBlock
|
||||||
|
&& direction == Direction.UP
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quads == null || quads.isEmpty())
|
||||||
|
{
|
||||||
|
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
||||||
|
getBlockModel(this.blockState).getQuads(this.blockState, null, RANDOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quads != null && !quads.isEmpty())
|
||||||
|
{
|
||||||
|
this.needPostTinting = quads.get(0).isTinted();
|
||||||
|
this.needShade = quads.get(0).isShade();
|
||||||
|
this.tintIndex = quads.get(0).getTintIndex();
|
||||||
|
this.baseColor = calculateColorFromTexture(
|
||||||
|
#if MC_VER < MC_1_17_1 quads.get(0).sprite,
|
||||||
|
#else quads.get(0).getSprite(), #endif
|
||||||
|
ColorMode.getColorMode(this.blockState.getBlock()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Backup method.
|
||||||
|
this.needPostTinting = false;
|
||||||
|
this.needShade = false;
|
||||||
|
this.tintIndex = 0;
|
||||||
|
this.baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState),
|
||||||
|
ColorMode.getColorMode(this.blockState.getBlock()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Liquid Block
|
||||||
|
this.needPostTinting = true;
|
||||||
|
this.needShade = false;
|
||||||
|
this.tintIndex = 0;
|
||||||
|
this.baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState),
|
||||||
|
ColorMode.getColorMode(this.blockState.getBlock()));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isColorResolved = true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
RESOLVE_LOCK.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO: Perhaps make this not just use the first frame?
|
||||||
|
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
int alpha = 0;
|
||||||
|
double red = 0;
|
||||||
|
double green = 0;
|
||||||
|
double blue = 0;
|
||||||
|
int tempColor;
|
||||||
|
|
||||||
|
// don't render Chiseled blocks.
|
||||||
|
// Since ColorMode is set per block, you only need to check this once.
|
||||||
|
if (colorMode != ColorMode.Chisel)
|
||||||
|
{
|
||||||
|
// textures normally use u and v instead of x and y
|
||||||
|
for (int v = 0; v < getTextureHeight(texture); v++)
|
||||||
|
{
|
||||||
|
for (int u = 0; u < getTextureWidth(texture); u++)
|
||||||
|
{
|
||||||
|
//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);
|
||||||
|
|
||||||
|
int r = (tempColor & 0x000000FF);
|
||||||
|
int g = (tempColor & 0x0000FF00) >>> 8;
|
||||||
|
int b = (tempColor & 0x00FF0000) >>> 16;
|
||||||
|
int a = (tempColor & 0xFF000000) >>> 24;
|
||||||
|
int scale = 1;
|
||||||
|
if (colorMode == ColorMode.Leaves)
|
||||||
|
{
|
||||||
|
//switch (//FIXME add config option)
|
||||||
|
// case BLACK:
|
||||||
|
// a = 255; //simulate black background of fast leaves
|
||||||
|
// break;
|
||||||
|
// case IGNORE:
|
||||||
|
if (a == 0) {
|
||||||
|
continue; //same long grass
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a = 255; //just in case there are semi transparent pixels
|
||||||
|
}
|
||||||
|
// break;
|
||||||
|
// case TRANSPARENT:
|
||||||
|
// break; //do nothing, let it count towards transparency
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (a == 0 && colorMode != ColorMode.Glass)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (colorMode == ColorMode.Flower && (g + 25 < b || g + 25 < r))
|
||||||
|
{
|
||||||
|
scale = FLOWER_COLOR_SCALE;
|
||||||
|
}
|
||||||
|
count += scale;
|
||||||
|
//apparently alpha is linear
|
||||||
|
alpha += a * scale;
|
||||||
|
//gamma correction is complicated
|
||||||
|
red += srgbToLinearTable[r] * a * scale;
|
||||||
|
green += srgbToLinearTable[g] * a * scale;
|
||||||
|
blue += srgbToLinearTable[b] * a * scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
// this block is entirely transparent
|
||||||
|
tempColor = ColorUtil.rgbToInt(0, 255, 255, 255);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// determine the average color
|
||||||
|
tempColor = ColorUtil.rgbToInt(
|
||||||
|
alpha / count,
|
||||||
|
linearToSrgb((float) (red / (double) alpha)),
|
||||||
|
linearToSrgb((float) (green / (double) alpha)),
|
||||||
|
linearToSrgb((float) (blue / (double) alpha)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if not missing texture
|
||||||
|
if (tempColor == ColorUtil.rgbToInt(255, 182, 0, 182))
|
||||||
|
{
|
||||||
|
//make it not render at all
|
||||||
|
tempColor = ColorUtil.rgbToInt(0, 255, 255, 255);
|
||||||
|
}
|
||||||
|
return tempColor;
|
||||||
|
}
|
||||||
|
private static int getTextureWidth(TextureAtlasSprite texture)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_19_4
|
||||||
|
return texture.getWidth();
|
||||||
|
#else
|
||||||
|
return texture.contents().width();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
private static int getTextureHeight(TextureAtlasSprite texture)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_19_4
|
||||||
|
return texture.getHeight();
|
||||||
|
#else
|
||||||
|
return texture.contents().height();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This method was suggested by IMS from the Iris/Sodium team.
|
||||||
|
* That's where the numbers and code are based.
|
||||||
|
*/
|
||||||
|
private static int linearToSrgb(float c)
|
||||||
|
{
|
||||||
|
if (!(c > MIN_SRGB_BOUND)) {
|
||||||
|
c = MIN_SRGB_BOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c > MAX_SRGB_BOUND) {
|
||||||
|
c = MAX_SRGB_BOUND;
|
||||||
|
}
|
||||||
|
int inputBits = Float.floatToRawIntBits(c);
|
||||||
|
int entry = linearToSrgbTable[((inputBits - MIN_SRGB_BITS) >> 20)];
|
||||||
|
|
||||||
|
int bias = (entry >>> 16) << 9;
|
||||||
|
int scale = entry & 0xffff;
|
||||||
|
int t = (inputBits >>> 12) & 0xff;
|
||||||
|
|
||||||
|
return (bias + (scale * t)) >>> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===============//
|
||||||
|
// public getter //
|
||||||
|
//===============//
|
||||||
|
|
||||||
|
public int getColor(BiomeWrapper biome, DhBlockPos pos)
|
||||||
|
{
|
||||||
|
// only get the tint if the block needs to be tinted
|
||||||
|
if (!this.needPostTinting)
|
||||||
|
{
|
||||||
|
return this.baseColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't try tinting blocks that don't support our method of tint getting
|
||||||
|
if (BROKEN_BLOCK_STATES.contains(this.blockState))
|
||||||
|
{
|
||||||
|
return this.baseColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// attempt to get the tint
|
||||||
|
int tintColor = -1;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// try to use the fast tint getter logic first
|
||||||
|
if (!BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tintColor = Minecraft.getInstance().getBlockColors()
|
||||||
|
.getColor(this.blockState, new TintWithoutLevelOverrider(biome, this.levelWrapper), McObjectConverter.Convert(pos), this.tintIndex);
|
||||||
|
}
|
||||||
|
catch (UnsupportedOperationException e)
|
||||||
|
{
|
||||||
|
// this exception generally occurs if the tint requires other blocks besides itself
|
||||||
|
LOGGER.debug("Unable to use ["+TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e);
|
||||||
|
BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use the level logic only if requested
|
||||||
|
if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
|
||||||
|
{
|
||||||
|
// this logic can't be used all the time due to it breaking some blocks tinting
|
||||||
|
// specifically oceans don't render correctly
|
||||||
|
tintColor = Minecraft.getInstance().getBlockColors()
|
||||||
|
.getColor(this.blockState, new TintGetterOverrideFast(this.level), McObjectConverter.Convert(pos), this.tintIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// only display the error once per block/biome type to reduce log spam
|
||||||
|
if (!BROKEN_BLOCK_STATES.contains(this.blockState))
|
||||||
|
{
|
||||||
|
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
|
||||||
|
BROKEN_BLOCK_STATES.add(this.blockState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (tintColor != -1)
|
||||||
|
{
|
||||||
|
return ColorUtil.multiplyARGBwithRGB(this.baseColor, tintColor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// unable to get the tinted color, use the base color instead
|
||||||
|
return this.baseColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper classes //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
enum ColorMode
|
||||||
|
{
|
||||||
|
Default,
|
||||||
|
Flower,
|
||||||
|
Leaves,
|
||||||
|
Chisel,
|
||||||
|
Glass;
|
||||||
|
|
||||||
|
static ColorMode getColorMode(Block block)
|
||||||
|
{
|
||||||
|
if (block instanceof LeavesBlock) return Leaves;
|
||||||
|
if (block instanceof FlowerBlock) return Flower;
|
||||||
|
if (block.toString().contains("glass")) return Glass;
|
||||||
|
if (block.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel;
|
||||||
|
return Default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
-48
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod
|
|
||||||
* licensed under the GNU LGPL v3 License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020-2023 James Seibel
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.block.cache;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
|
||||||
import com.seibel.distanthorizons.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 MC_VER < 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, pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() { blockCache.clear(); }
|
|
||||||
|
|
||||||
public int getColor(BlockState state, BiomeWrapper biome, DhBlockPos pos)
|
|
||||||
{
|
|
||||||
return getBlockStateData(state, pos).getAndResolveFaceColor(biome, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-412
@@ -1,412 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod
|
|
||||||
* licensed under the GNU LGPL v3 License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020-2023 James Seibel
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.block.cache;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.TextureAtlasSpriteWrapper;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.TintWithoutLevelOverrider;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.*;
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
|
||||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
|
||||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
|
||||||
import com.seibel.distanthorizons.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 MC_VER >= MC_1_19_2
|
|
||||||
import net.minecraft.util.RandomSource;
|
|
||||||
#else
|
|
||||||
import java.util.Random;
|
|
||||||
#endif
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @version 2022-9-16
|
|
||||||
*/
|
|
||||||
public class ClientBlockStateCache
|
|
||||||
{
|
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
|
||||||
|
|
||||||
private static final HashSet<BlockState> BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>();
|
|
||||||
private static final HashSet<BlockState> BROKEN_BLOCK_STATES = new HashSet<>();
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_2
|
|
||||||
public static final Random random = new Random(0);
|
|
||||||
#else
|
|
||||||
public static final RandomSource random = RandomSource.create();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public final IClientLevelWrapper levelWrapper;
|
|
||||||
public final BlockState blockState;
|
|
||||||
public final LevelReader level;
|
|
||||||
public final BlockPos pos;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public ClientBlockStateCache(BlockState blockState, IClientLevelWrapper samplingLevel, DhBlockPos samplingPos)
|
|
||||||
{
|
|
||||||
this.blockState = blockState;
|
|
||||||
this.levelWrapper = samplingLevel;
|
|
||||||
this.level = (LevelReader) samplingLevel.getWrappedMcObject();
|
|
||||||
this.pos = McObjectConverter.Convert(samplingPos);
|
|
||||||
this.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,
|
|
||||||
Chisel,
|
|
||||||
Glass;
|
|
||||||
static ColorMode getColorMode(Block b)
|
|
||||||
{
|
|
||||||
if (b instanceof LeavesBlock) return Leaves;
|
|
||||||
if (b instanceof FlowerBlock) return Flower;
|
|
||||||
if (b.toString().contains("glass")) return Glass;
|
|
||||||
if (b.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel;
|
|
||||||
return Default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Way to efficiently do this was suggested by IMS from sodium. This is where those numbers and support code was lifted from.
|
|
||||||
private static final int MIN_BITS = 0x39000000; // 2^(-13)
|
|
||||||
private static final int MAX_BITS = 0x3f7fffff; // 1.0 - f32::EPSILON
|
|
||||||
private static final float MIN_BOUND = Float.intBitsToFloat(MIN_BITS);
|
|
||||||
private static final float MAX_BOUND = Float.intBitsToFloat(MAX_BITS);
|
|
||||||
|
|
||||||
private static final int[] linearToSrgbTable = new int[] {
|
|
||||||
0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
|
|
||||||
0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
|
|
||||||
0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
|
|
||||||
0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
|
|
||||||
0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
|
|
||||||
0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
|
|
||||||
0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
|
|
||||||
0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
|
|
||||||
0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
|
|
||||||
0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
|
|
||||||
0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
|
|
||||||
0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
|
|
||||||
0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final float[] srgbToLinearTable = new float[] {
|
|
||||||
0.0f, 0.000303527f, 0.000607054f, 0.00091058103f, 0.001214108f, 0.001517635f, 0.0018211621f, 0.002124689f,
|
|
||||||
0.002428216f, 0.002731743f, 0.00303527f, 0.0033465356f, 0.003676507f, 0.004024717f, 0.004391442f,
|
|
||||||
0.0047769533f, 0.005181517f, 0.0056053917f, 0.0060488326f, 0.006512091f, 0.00699541f, 0.0074990317f,
|
|
||||||
0.008023192f, 0.008568125f, 0.009134057f, 0.009721218f, 0.010329823f, 0.010960094f, 0.011612245f,
|
|
||||||
0.012286487f, 0.012983031f, 0.013702081f, 0.014443844f, 0.015208514f, 0.015996292f, 0.016807375f,
|
|
||||||
0.017641952f, 0.018500218f, 0.019382361f, 0.020288562f, 0.02121901f, 0.022173883f, 0.023153365f,
|
|
||||||
0.02415763f, 0.025186857f, 0.026241222f, 0.027320892f, 0.028426038f, 0.029556843f, 0.03071345f, 0.03189604f,
|
|
||||||
0.033104774f, 0.03433981f, 0.035601325f, 0.036889452f, 0.038204376f, 0.039546248f, 0.04091521f, 0.042311423f,
|
|
||||||
0.043735042f, 0.045186214f, 0.046665095f, 0.048171833f, 0.049706575f, 0.051269468f, 0.052860655f, 0.05448028f,
|
|
||||||
0.056128494f, 0.057805434f, 0.05951124f, 0.06124607f, 0.06301003f, 0.06480328f, 0.06662595f, 0.06847818f,
|
|
||||||
0.07036011f, 0.07227186f, 0.07421358f, 0.07618539f, 0.07818743f, 0.08021983f, 0.082282715f, 0.084376216f,
|
|
||||||
0.086500466f, 0.088655606f, 0.09084173f, 0.09305898f, 0.095307484f, 0.09758736f, 0.09989874f, 0.10224175f,
|
|
||||||
0.10461649f, 0.10702311f, 0.10946172f, 0.111932434f, 0.11443538f, 0.116970696f, 0.11953845f, 0.12213881f,
|
|
||||||
0.12477186f, 0.12743773f, 0.13013652f, 0.13286836f, 0.13563336f, 0.13843165f, 0.14126332f, 0.1441285f,
|
|
||||||
0.1470273f, 0.14995982f, 0.15292618f, 0.1559265f, 0.15896086f, 0.16202943f, 0.16513224f, 0.16826946f,
|
|
||||||
0.17144115f, 0.17464745f, 0.17788847f, 0.1811643f, 0.18447503f, 0.1878208f, 0.19120172f, 0.19461787f,
|
|
||||||
0.19806935f, 0.2015563f, 0.20507877f, 0.2086369f, 0.21223079f, 0.21586053f, 0.21952623f, 0.22322798f,
|
|
||||||
0.22696589f, 0.23074007f, 0.23455065f, 0.23839766f, 0.2422812f, 0.2462014f, 0.25015837f, 0.25415218f,
|
|
||||||
0.2581829f, 0.26225072f, 0.26635566f, 0.27049786f, 0.27467737f, 0.27889434f, 0.2831488f, 0.2874409f,
|
|
||||||
0.2917707f, 0.29613832f, 0.30054384f, 0.30498737f, 0.30946895f, 0.31398875f, 0.31854683f, 0.32314324f,
|
|
||||||
0.32777813f, 0.33245158f, 0.33716366f, 0.34191445f, 0.3467041f, 0.3515327f, 0.35640025f, 0.36130688f,
|
|
||||||
0.3662527f, 0.37123778f, 0.37626222f, 0.3813261f, 0.38642952f, 0.39157256f, 0.3967553f, 0.40197787f,
|
|
||||||
0.4072403f, 0.4125427f, 0.41788515f, 0.42326775f, 0.42869055f, 0.4341537f, 0.43965724f, 0.44520125f,
|
|
||||||
0.45078585f, 0.45641106f, 0.46207705f, 0.46778384f, 0.47353154f, 0.47932023f, 0.48514998f, 0.4910209f,
|
|
||||||
0.49693304f, 0.5028866f, 0.50888145f, 0.5149178f, 0.5209957f, 0.52711535f, 0.5332766f, 0.5394797f,
|
|
||||||
0.5457247f, 0.5520116f, 0.5583406f, 0.5647117f, 0.57112503f, 0.57758063f, 0.5840786f, 0.590619f, 0.597202f,
|
|
||||||
0.60382754f, 0.61049575f, 0.61720675f, 0.62396055f, 0.63075733f, 0.637597f, 0.6444799f, 0.6514058f,
|
|
||||||
0.65837497f, 0.66538745f, 0.67244333f, 0.6795426f, 0.68668544f, 0.69387203f, 0.70110214f, 0.70837605f,
|
|
||||||
0.7156938f, 0.72305536f, 0.730461f, 0.7379107f, 0.7454045f, 0.75294244f, 0.76052475f, 0.7681514f, 0.77582246f,
|
|
||||||
0.78353804f, 0.79129815f, 0.79910296f, 0.8069525f, 0.8148468f, 0.822786f, 0.8307701f, 0.83879924f, 0.84687346f,
|
|
||||||
0.8549928f, 0.8631574f, 0.87136734f, 0.8796226f, 0.8879232f, 0.89626956f, 0.90466136f, 0.913099f, 0.92158204f,
|
|
||||||
0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f
|
|
||||||
};
|
|
||||||
|
|
||||||
private static int linearToSrgb(float c) {
|
|
||||||
if (!(c > MIN_BOUND)) {
|
|
||||||
c = MIN_BOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c > MAX_BOUND) {
|
|
||||||
c = MAX_BOUND;
|
|
||||||
}
|
|
||||||
int inputBits = Float.floatToRawIntBits(c);
|
|
||||||
int entry = linearToSrgbTable[((inputBits - MIN_BITS) >> 20)];
|
|
||||||
|
|
||||||
int bias = (entry >>> 16) << 9;
|
|
||||||
int scale = entry & 0xffff;
|
|
||||||
int t = (inputBits >>> 12) & 0xff;
|
|
||||||
|
|
||||||
return (bias + (scale * t)) >>> 16;
|
|
||||||
}
|
|
||||||
//////////////
|
|
||||||
|
|
||||||
private static int getWidth(TextureAtlasSprite texture)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_19_4
|
|
||||||
return texture.getWidth();
|
|
||||||
#else
|
|
||||||
return texture.contents().width();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getHeight(TextureAtlasSprite texture)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_19_4
|
|
||||||
return texture.getHeight();
|
|
||||||
#else
|
|
||||||
return texture.contents().height();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//TODO: Perhaps make this not just use the first frame?
|
|
||||||
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
int alpha = 0;
|
|
||||||
double red = 0;
|
|
||||||
double green = 0;
|
|
||||||
double blue = 0;
|
|
||||||
int tempColor;
|
|
||||||
//make Chiseled block not render. Since ColorMode is set per block, you only need to check it once
|
|
||||||
if (colorMode != ColorMode.Chisel)
|
|
||||||
{
|
|
||||||
// textures normally use u and v instead of x and y
|
|
||||||
for (int v = 0; v < getHeight(texture); v++)
|
|
||||||
{
|
|
||||||
for (int u = 0; u < getWidth(texture); u++)
|
|
||||||
{
|
|
||||||
//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);
|
|
||||||
|
|
||||||
int r = (tempColor & 0x000000FF);
|
|
||||||
int g = (tempColor & 0x0000FF00) >>> 8;
|
|
||||||
int b = (tempColor & 0x00FF0000) >>> 16;
|
|
||||||
int a = (tempColor & 0xFF000000) >>> 24;
|
|
||||||
int scale = 1;
|
|
||||||
if (colorMode == ColorMode.Leaves)
|
|
||||||
{
|
|
||||||
//switch (//FIXME add config option)
|
|
||||||
// case BLACK:
|
|
||||||
// a = 255; //simulate black background of fast leaves
|
|
||||||
// break;
|
|
||||||
// case IGNORE:
|
|
||||||
if (a == 0) {
|
|
||||||
continue; //same long grass
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a = 255; //just in case there are semi transparent pixels
|
|
||||||
}
|
|
||||||
// break;
|
|
||||||
// case TRANSPARENT:
|
|
||||||
// break; //do nothing, let it count towards transparency
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (a == 0 && colorMode != ColorMode.Glass)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (colorMode == ColorMode.Flower && (g + 25 < b || g + 25 < r))
|
|
||||||
{
|
|
||||||
scale = FLOWER_COLOR_SCALE;
|
|
||||||
}
|
|
||||||
count += scale;
|
|
||||||
//apparently alpha is linear
|
|
||||||
alpha += a * scale;
|
|
||||||
//gamma correction is complicated
|
|
||||||
red += srgbToLinearTable[r] * a * scale;
|
|
||||||
green += srgbToLinearTable[g] * a * scale;
|
|
||||||
blue += srgbToLinearTable[b] * a * scale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 0)
|
|
||||||
// this block is entirely transparent
|
|
||||||
tempColor = ColorUtil.rgbToInt(0, 255, 255, 255);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// determine the average color
|
|
||||||
tempColor = ColorUtil.rgbToInt(
|
|
||||||
alpha / count,
|
|
||||||
linearToSrgb((float) (red / (double) alpha)),
|
|
||||||
linearToSrgb((float) (green / (double) alpha)),
|
|
||||||
linearToSrgb((float) (blue / (double) alpha)));
|
|
||||||
}
|
|
||||||
//check if not missing texture
|
|
||||||
if (tempColor == ColorUtil.rgbToInt(255, 182, 0, 182))
|
|
||||||
{
|
|
||||||
//make it not render at all
|
|
||||||
tempColor = ColorUtil.rgbToInt(0, 255, 255, 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 (blockState.getFluidState().isEmpty())
|
|
||||||
{
|
|
||||||
List<BakedQuad> quads = null;
|
|
||||||
for (Direction direction : DIRECTION_ORDER)
|
|
||||||
{
|
|
||||||
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
|
||||||
getBlockModel(blockState).getQuads(blockState, direction, random); // TODO getQuads sometimes throws a "makeThreadingException", is there anything we can do about that? Note: this isn't a critical issue, it just prints an ugly error and the render data will need to be regenered.
|
|
||||||
if (quads != null && !quads.isEmpty() &&
|
|
||||||
!(blockState.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP))
|
|
||||||
break;
|
|
||||||
} ;
|
|
||||||
if (quads == null || quads.isEmpty())
|
|
||||||
{
|
|
||||||
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
|
||||||
getBlockModel(blockState).getQuads(blockState, 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 MC_VER < MC_1_17_1 quads.get(0).sprite,
|
|
||||||
#else quads.get(0).getSprite(), #endif
|
|
||||||
ColorMode.getColorMode(blockState.getBlock()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // Backup method.
|
|
||||||
needPostTinting = false;
|
|
||||||
needShade = false;
|
|
||||||
tintIndex = 0;
|
|
||||||
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(blockState),
|
|
||||||
ColorMode.getColorMode(blockState.getBlock()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // Liquid Block
|
|
||||||
needPostTinting = true;
|
|
||||||
needShade = false;
|
|
||||||
tintIndex = 0;
|
|
||||||
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(blockState),
|
|
||||||
ColorMode.getColorMode(blockState.getBlock()));
|
|
||||||
}
|
|
||||||
isColorResolved = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAndResolveFaceColor(BiomeWrapper biome, DhBlockPos pos)
|
|
||||||
{
|
|
||||||
// FIXME: impl per-face colors
|
|
||||||
|
|
||||||
// only get the tint if the block needs to be tinted
|
|
||||||
if (!this.needPostTinting)
|
|
||||||
{
|
|
||||||
return this.baseColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't try tinting blocks that don't support our method of tint getting
|
|
||||||
if (BROKEN_BLOCK_STATES.contains(this.blockState))
|
|
||||||
{
|
|
||||||
return this.baseColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// attempt to get the tint
|
|
||||||
int tintColor = -1;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// try to use the fast tint getter logic first
|
|
||||||
if (!BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
tintColor = Minecraft.getInstance().getBlockColors()
|
|
||||||
.getColor(this.blockState, new TintWithoutLevelOverrider(biome, this.levelWrapper), McObjectConverter.Convert(pos), this.tintIndex);
|
|
||||||
}
|
|
||||||
catch (UnsupportedOperationException e)
|
|
||||||
{
|
|
||||||
// this exception generally occurs if the tint requires other blocks besides itself
|
|
||||||
LOGGER.debug("Unable to use ["+TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e);
|
|
||||||
BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// use the level logic only if requested
|
|
||||||
if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
|
|
||||||
{
|
|
||||||
// this logic can't be used all the time due to it breaking some blocks tinting
|
|
||||||
// specifically oceans don't render correctly
|
|
||||||
tintColor = Minecraft.getInstance().getBlockColors()
|
|
||||||
.getColor(this.blockState, new TintGetterOverrideFast(this.level), McObjectConverter.Convert(pos), this.tintIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
// only display the error once per block/biome type to reduce log spam
|
|
||||||
if (!BROKEN_BLOCK_STATES.contains(this.blockState))
|
|
||||||
{
|
|
||||||
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
|
|
||||||
BROKEN_BLOCK_STATES.add(this.blockState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (tintColor != -1)
|
|
||||||
{
|
|
||||||
return ColorUtil.multiplyARGBwithRGB(this.baseColor, tintColor);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// unable to get the tinted color, use the base color instead
|
|
||||||
return this.baseColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-43
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod
|
|
||||||
* licensed under the GNU LGPL v3 License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020-2023 James Seibel
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.block.cache;
|
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
|
||||||
import com.seibel.distanthorizons.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 MC_VER < 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(); }
|
|
||||||
|
|
||||||
}
|
|
||||||
-104
@@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod
|
|
||||||
* licensed under the GNU LGPL v3 License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020-2023 James Seibel
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.block.cache;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
|
||||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
|
||||||
import com.seibel.distanthorizons.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();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-239
@@ -1,239 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod
|
|
||||||
* licensed under the GNU LGPL v3 License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020-2023 James Seibel
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.chunk;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.coreapi.util.BitShiftUtil;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compact, efficient storage for light levels.
|
|
||||||
* all blocks only take up 4 bits in total,
|
|
||||||
* and if a 16x16x16 area is detected to have the same light level in all positions,
|
|
||||||
* then we store a single byte for that light level, instead of 2 kilobytes.
|
|
||||||
*
|
|
||||||
* @author Builderb0y
|
|
||||||
*/
|
|
||||||
public class ChunkLightStorage
|
|
||||||
{
|
|
||||||
/** the minimum Y level in the chunk which this storage is storing light levels for (inclusive). */
|
|
||||||
public int minY;
|
|
||||||
/** the maximum Y level in the chunk which this storage is storing light levels for (exclusive). */
|
|
||||||
public int maxY;
|
|
||||||
|
|
||||||
/** the data stored in this storage, split up into 16x16x16 areas. */
|
|
||||||
public LightSection[] lightSections;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the get method is called on a Y position above what's stored
|
|
||||||
* this value will be returned. <br><br>
|
|
||||||
*
|
|
||||||
* This needs to be manually defined since sky and block lights behave differently
|
|
||||||
* for values both above and below what's defined.
|
|
||||||
*/
|
|
||||||
public int aboveMaxYValue;
|
|
||||||
/** @see ChunkLightStorage#aboveMaxYValue */
|
|
||||||
public int belowMinYValue;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=============//
|
|
||||||
// constructor //
|
|
||||||
//=============//
|
|
||||||
|
|
||||||
public ChunkLightStorage(int minY, int maxY, int aboveMaxYValue, int belowMinYValue)
|
|
||||||
{
|
|
||||||
this.minY = minY;
|
|
||||||
this.maxY = maxY;
|
|
||||||
|
|
||||||
this.aboveMaxYValue = aboveMaxYValue;
|
|
||||||
this.belowMinYValue = belowMinYValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=====================//
|
|
||||||
// getters and setters //
|
|
||||||
//=====================//
|
|
||||||
|
|
||||||
public int get(int x, int y, int z)
|
|
||||||
{
|
|
||||||
if (y < this.minY)
|
|
||||||
{
|
|
||||||
return this.belowMinYValue;
|
|
||||||
}
|
|
||||||
else if (y >= this.maxY)
|
|
||||||
{
|
|
||||||
return this.aboveMaxYValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (this.lightSections != null)
|
|
||||||
{
|
|
||||||
LightSection lightSection = this.lightSections[BitShiftUtil.divideByPowerOfTwo(y - this.minY, 4)];
|
|
||||||
if (lightSection != null)
|
|
||||||
{
|
|
||||||
return lightSection.get(x, y, z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(int x, int y, int z, int lightLevel)
|
|
||||||
{
|
|
||||||
if (y < this.minY || y >= this.maxY)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//populate array if it doesn't exist.
|
|
||||||
if (this.lightSections == null)
|
|
||||||
{
|
|
||||||
this.lightSections = new LightSection[BitShiftUtil.divideByPowerOfTwo(this.maxY - this.minY, 4)];
|
|
||||||
}
|
|
||||||
|
|
||||||
int index = (y - this.minY) >> 4;
|
|
||||||
LightSection lightSection = this.lightSections[index];
|
|
||||||
|
|
||||||
//populate lightSection in array if it doesn't exist.
|
|
||||||
if (lightSection == null)
|
|
||||||
{
|
|
||||||
lightSection = new LightSection(0);
|
|
||||||
this.lightSections[index] = lightSection;
|
|
||||||
}
|
|
||||||
lightSection.set(x, y, z, lightLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
|
||||||
// helper classes //
|
|
||||||
//================//
|
|
||||||
|
|
||||||
public static class LightSection
|
|
||||||
{
|
|
||||||
public byte constantValue;
|
|
||||||
public long[] data;
|
|
||||||
public short[] counts;
|
|
||||||
|
|
||||||
public LightSection(int initialValue)
|
|
||||||
{
|
|
||||||
this.constantValue = (byte) (initialValue);
|
|
||||||
this.counts = new short[16];
|
|
||||||
this.counts[initialValue] = 16 * 16 * 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int get(int x, int y, int z)
|
|
||||||
{
|
|
||||||
if (this.constantValue >= 0)
|
|
||||||
{
|
|
||||||
return this.constantValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
x &= 15;
|
|
||||||
y &= 15;
|
|
||||||
z &= 15;
|
|
||||||
long bits = this.data[(z << 4) | x];
|
|
||||||
return ((int) (bits >>> (y << 2))) & 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(int x, int y, int z, int lightLevel)
|
|
||||||
{
|
|
||||||
int oldLightLevel = -1;
|
|
||||||
if (this.constantValue >= 0)
|
|
||||||
{
|
|
||||||
oldLightLevel = this.constantValue;
|
|
||||||
|
|
||||||
//if the light level didn't change, then there's nothing to do.
|
|
||||||
if (oldLightLevel == lightLevel) return;
|
|
||||||
|
|
||||||
//if we are a constant value and need to change something,
|
|
||||||
//then that means we need to convert to a non-constant value.
|
|
||||||
this.data = DataRecycler.get();
|
|
||||||
|
|
||||||
//repeat oldLightLevel 16 times as a bit pattern.
|
|
||||||
long payload = oldLightLevel;
|
|
||||||
payload |= payload << 4;
|
|
||||||
payload |= payload << 8;
|
|
||||||
payload |= payload << 16;
|
|
||||||
payload |= payload << 32;
|
|
||||||
|
|
||||||
//fill our data with our constant value.
|
|
||||||
Arrays.fill(this.data, payload);
|
|
||||||
|
|
||||||
//we are no longer a constant value.
|
|
||||||
this.constantValue = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
x &= 15;
|
|
||||||
y &= 15;
|
|
||||||
z &= 15;
|
|
||||||
int index = (z << 4) | x;
|
|
||||||
long bits = this.data[index];
|
|
||||||
//if we weren't a constant value before, now's the time to initialize oldLightLevel.
|
|
||||||
if (oldLightLevel < 0)
|
|
||||||
{
|
|
||||||
oldLightLevel = ((int) (bits >>> (y << 2))) & 15;
|
|
||||||
}
|
|
||||||
//clear the 4 bits that correspond to the light level at x, y, z...
|
|
||||||
bits &= ~(15L << (y << 2));
|
|
||||||
//...and then re-populate those bits with the new light level.
|
|
||||||
bits |= ((long) (lightLevel)) << (y << 2);
|
|
||||||
//store the updated bits in our data.
|
|
||||||
this.data[index] = bits;
|
|
||||||
|
|
||||||
//we have one less of the old light level...
|
|
||||||
this.counts[oldLightLevel]--;
|
|
||||||
//...and one more of the new level.
|
|
||||||
//if the number associated with the new level is now 4096 (AKA 16 ^ 3),
|
|
||||||
//then this implies every position in this section has the same light level,
|
|
||||||
//and therefore we can convert back to a constant value.
|
|
||||||
if (++this.counts[lightLevel] == 4096)
|
|
||||||
{
|
|
||||||
this.constantValue = (byte) (lightLevel);
|
|
||||||
DataRecycler.reclaim(this.data);
|
|
||||||
this.data = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class DataRecycler
|
|
||||||
{
|
|
||||||
private static final ArrayList<long[]> recycled = new ArrayList<>(256);
|
|
||||||
|
|
||||||
static synchronized long[] get()
|
|
||||||
{
|
|
||||||
if (recycled.isEmpty())
|
|
||||||
{
|
|
||||||
return new long[256];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return recycled.remove(recycled.size() - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static synchronized void reclaim(long[] data) { if (recycled.size() < 256) recycled.add(data); }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+107
-132
@@ -22,16 +22,18 @@ package com.seibel.distanthorizons.common.wrappers.chunk;
|
|||||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.world.EWorldEnvironment;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
|
||||||
import net.minecraft.client.multiplayer.ClientChunkCache;
|
import net.minecraft.client.multiplayer.ClientChunkCache;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
@@ -83,9 +85,6 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
{
|
{
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||||
|
|
||||||
/** useful for debugging, but can slow down chunk operations quite a bit due to being called every time. */
|
|
||||||
private static final boolean RUN_RELATIVE_POS_INDEX_VALIDATION = ModInfo.IS_DEV_BUILD;
|
|
||||||
|
|
||||||
/** can be used for interactions with the underlying chunk where creating new BlockPos objects could cause issues for the garbage collector. */
|
/** can be used for interactions with the underlying chunk where creating new BlockPos objects could cause issues for the garbage collector. */
|
||||||
private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos());
|
private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos());
|
||||||
|
|
||||||
@@ -109,6 +108,8 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
private int minNonEmptyHeight = Integer.MIN_VALUE;
|
private int minNonEmptyHeight = Integer.MIN_VALUE;
|
||||||
private int maxNonEmptyHeight = Integer.MAX_VALUE;
|
private int maxNonEmptyHeight = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
private int blockBiomeHashCode = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Due to vanilla `isClientLightReady()` not being designed for use by a non-render thread, it may return 'true'
|
* Due to vanilla `isClientLightReady()` not being designed for use by a non-render thread, it may return 'true'
|
||||||
* before the light engine has ticked, (right after all light changes is marked by the engine to be processed).
|
* before the light engine has ticked, (right after all light changes is marked by the engine to be processed).
|
||||||
@@ -142,36 +143,41 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
|
|
||||||
// FIXME +1 is to handle the fact that LodDataBuilder adds +1 to all block lighting calculations, also done in the relative position validator
|
// FIXME +1 is to handle the fact that LodDataBuilder adds +1 to all block lighting calculations, also done in the relative position validator
|
||||||
|
|
||||||
chunksNeedingClientLightUpdating.add(this);
|
if (SharedApi.getEnvironment() != EWorldEnvironment.Server_Only)
|
||||||
|
chunksNeedingClientLightUpdating.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=========//
|
//=========//
|
||||||
// methods //
|
// getters //
|
||||||
//=========//
|
//=========//
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getHeight()
|
public int getHeight() { return getHeight(this.chunk); }
|
||||||
|
public static int getHeight(ChunkAccess chunk)
|
||||||
{
|
{
|
||||||
#if MC_VER < MC_1_17_1
|
#if MC_VER < MC_1_17_1
|
||||||
return 255;
|
return 255;
|
||||||
#else
|
#else
|
||||||
return this.chunk.getHeight();
|
return chunk.getHeight();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMinBuildHeight()
|
public int getMinBuildHeight() { return getMinBuildHeight(this.chunk); }
|
||||||
|
public static int getMinBuildHeight(ChunkAccess chunk)
|
||||||
{
|
{
|
||||||
#if MC_VER < MC_1_17_1
|
#if MC_VER < MC_1_17_1
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
return this.chunk.getMinBuildHeight();
|
return chunk.getMinBuildHeight();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMaxBuildHeight() { return this.chunk.getMaxBuildHeight(); }
|
public int getMaxBuildHeight() { return getMaxBuildHeight(this.chunk); }
|
||||||
|
public static int getMaxBuildHeight(ChunkAccess chunk) { return chunk.getMaxBuildHeight(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMinNonEmptyHeight()
|
public int getMinNonEmptyHeight()
|
||||||
@@ -221,6 +227,9 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
LevelChunkSection[] sections = this.chunk.getSections();
|
LevelChunkSection[] sections = this.chunk.getSections();
|
||||||
for (int index = sections.length-1; index >= 0; index--)
|
for (int index = sections.length-1; index >= 0; index--)
|
||||||
{
|
{
|
||||||
|
// update at each position to fix using the max height if the chunk is empty
|
||||||
|
this.maxNonEmptyHeight = this.getChunkSectionMinHeight(index) + 16;
|
||||||
|
|
||||||
if (sections[index] == null)
|
if (sections[index] == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -228,7 +237,7 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
|
|
||||||
if (!isChunkSectionEmpty(sections[index]))
|
if (!isChunkSectionEmpty(sections[index]))
|
||||||
{
|
{
|
||||||
this.maxNonEmptyHeight = this.getChunkSectionMinHeight(index) + 16;
|
// non-empty section found
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,15 +254,7 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
return section.hasOnlyAir();
|
return section.hasOnlyAir();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
private int getChunkSectionMinHeight(int index)
|
private int getChunkSectionMinHeight(int index) { return (index * 16) + this.getMinBuildHeight(); }
|
||||||
{
|
|
||||||
// convert from an index to a block coordinate
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
|
||||||
return this.chunk.getSections()[index].bottomBlockY();
|
|
||||||
#else
|
|
||||||
return this.chunk.getSectionYFromSectionIndex(index) * 16;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -263,7 +264,6 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
public int getLightBlockingHeightMapValue(int xRel, int zRel) { return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING).getFirstAvailable(xRel, zRel); }
|
public int getLightBlockingHeightMapValue(int xRel, int zRel) { return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING).getFirstAvailable(xRel, zRel); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBiomeWrapper getBiome(int relX, int relY, int relZ)
|
public IBiomeWrapper getBiome(int relX, int relY, int relZ)
|
||||||
{
|
{
|
||||||
@@ -287,11 +287,35 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBlockStateWrapper getBlockState(int relX, int relY, int relZ)
|
||||||
|
{
|
||||||
|
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
|
||||||
|
|
||||||
|
BlockPos.MutableBlockPos blockPos = MUTABLE_BLOCK_POS_REF.get();
|
||||||
|
|
||||||
|
blockPos.setX(relX);
|
||||||
|
blockPos.setY(relY);
|
||||||
|
blockPos.setZ(relZ);
|
||||||
|
|
||||||
|
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DhChunkPos getChunkPos() { return this.chunkPos; }
|
public DhChunkPos getChunkPos() { return this.chunkPos; }
|
||||||
|
|
||||||
public ChunkAccess getChunk() { return this.chunk; }
|
public ChunkAccess getChunk() { return this.chunk; }
|
||||||
|
|
||||||
|
public ChunkStatus getStatus() { return getStatus(this.getChunk()); }
|
||||||
|
public static ChunkStatus getStatus(ChunkAccess chunk)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
return chunk.getStatus();
|
||||||
|
#else
|
||||||
|
return chunk.getPersistedStatus();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMaxBlockX() { return this.chunk.getPos().getMaxBlockX(); }
|
public int getMaxBlockX() { return this.chunk.getPos().getMaxBlockX(); }
|
||||||
@Override
|
@Override
|
||||||
@@ -301,8 +325,11 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
@Override
|
@Override
|
||||||
public int getMinBlockZ() { return this.chunk.getPos().getMinBlockZ(); }
|
public int getMinBlockZ() { return this.chunk.getPos().getMinBlockZ(); }
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getLongChunkPos() { return this.chunk.getPos().toLong(); }
|
|
||||||
|
//==========//
|
||||||
|
// lighting //
|
||||||
|
//==========//
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIsDhLightCorrect(boolean isDhLightCorrect) { this.isDhLightCorrect = isDhLightCorrect; }
|
public void setIsDhLightCorrect(boolean isDhLightCorrect) { this.isDhLightCorrect = isDhLightCorrect; }
|
||||||
@@ -310,8 +337,6 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
@Override
|
@Override
|
||||||
public void setUseDhLighting(boolean useDhLighting) { this.useDhLighting = useDhLighting; }
|
public void setUseDhLighting(boolean useDhLighting) { this.useDhLighting = useDhLighting; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLightCorrect()
|
public boolean isLightCorrect()
|
||||||
{
|
{
|
||||||
@@ -327,7 +352,7 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
if (this.chunk instanceof LevelChunk)
|
if (this.chunk instanceof LevelChunk)
|
||||||
{
|
{
|
||||||
LevelChunk levelChunk = (LevelChunk) this.chunk;
|
LevelChunk levelChunk = (LevelChunk) this.chunk;
|
||||||
if (levelChunk.getLevel() instanceof ClientLevel)
|
if (levelChunk.getLevel().isClientSide())
|
||||||
{
|
{
|
||||||
// connected to a server
|
// connected to a server
|
||||||
return this.isMcClientLightingCorrect;
|
return this.isMcClientLightingCorrect;
|
||||||
@@ -364,13 +389,13 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
{
|
{
|
||||||
if (this.blockLightStorage == null)
|
if (this.blockLightStorage == null)
|
||||||
{
|
{
|
||||||
this.blockLightStorage = new ChunkLightStorage(
|
this.blockLightStorage = ChunkLightStorage.createBlockLightStorage(this);
|
||||||
this.getMinBuildHeight(), this.getMaxBuildHeight(),
|
|
||||||
// positions above and below the handled area should be unlit
|
|
||||||
LodUtil.MIN_MC_LIGHT, LodUtil.MIN_MC_LIGHT);
|
|
||||||
}
|
}
|
||||||
return this.blockLightStorage;
|
return this.blockLightStorage;
|
||||||
}
|
}
|
||||||
|
public void setBlockLightStorage(ChunkLightStorage lightStorage) { this.blockLightStorage = lightStorage; }
|
||||||
|
@Override
|
||||||
|
public void clearDhBlockLighting() { this.getBlockLightStorage().clear(); }
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -385,18 +410,18 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
|
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
|
||||||
this.getSkyLightStorage().set(relX, y, relZ, lightValue);
|
this.getSkyLightStorage().set(relX, y, relZ, lightValue);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public void clearDhSkyLighting() { this.getSkyLightStorage().clear(); }
|
||||||
|
|
||||||
private ChunkLightStorage getSkyLightStorage()
|
private ChunkLightStorage getSkyLightStorage()
|
||||||
{
|
{
|
||||||
if (this.skyLightStorage == null)
|
if (this.skyLightStorage == null)
|
||||||
{
|
{
|
||||||
this.skyLightStorage = new ChunkLightStorage(
|
this.skyLightStorage = ChunkLightStorage.createSkyLightStorage(this);
|
||||||
this.getMinBuildHeight(), this.getMaxBuildHeight(),
|
|
||||||
// positions above should be lit but positions below should be unlit
|
|
||||||
LodUtil.MAX_MC_LIGHT, LodUtil.MIN_MC_LIGHT);
|
|
||||||
}
|
}
|
||||||
return this.skyLightStorage;
|
return this.skyLightStorage;
|
||||||
}
|
}
|
||||||
|
public void setSkyLightStorage(ChunkLightStorage lightStorage) { this.skyLightStorage = lightStorage; }
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -442,7 +467,7 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
* before the list has finished populating.
|
* before the list has finished populating.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized ArrayList<DhBlockPos> getBlockLightPosList()
|
public synchronized ArrayList<DhBlockPos> getWorldBlockLightPosList()
|
||||||
{
|
{
|
||||||
// only populate the list once
|
// only populate the list once
|
||||||
if (this.blockLightPosList == null)
|
if (this.blockLightPosList == null)
|
||||||
@@ -458,7 +483,13 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
#else
|
#else
|
||||||
this.chunk.findBlockLightSources((blockPos, blockState) ->
|
this.chunk.findBlockLightSources((blockPos, blockState) ->
|
||||||
{
|
{
|
||||||
this.blockLightPosList.add(new DhBlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ()));
|
DhBlockPos pos = new DhBlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
||||||
|
|
||||||
|
// this can be uncommented if MC decides to return relative block positions in the future instead of world positions
|
||||||
|
//pos.mutateToChunkRelativePos(pos);
|
||||||
|
//pos.mutateOffset(this.chunkPos.getMinBlockX(), 0, this.chunkPos.getMinBlockZ(), pos);
|
||||||
|
|
||||||
|
this.blockLightPosList.add(pos);
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -466,55 +497,6 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
return this.blockLightPosList;
|
return this.blockLightPosList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean doNearbyChunksExist()
|
|
||||||
{
|
|
||||||
if (this.lightSource instanceof DhLitWorldGenRegion)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int dx = -1; dx <= 1; dx++)
|
|
||||||
{
|
|
||||||
for (int dz = -1; dz <= 1; dz++)
|
|
||||||
{
|
|
||||||
if (dx == 0 && dz == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (this.lightSource.getChunk(dx + this.chunk.getPos().x, dz + this.chunk.getPos().z, ChunkStatus.BIOMES, false) == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LevelReader getColorResolver() { return this.lightSource; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() { return this.chunk.getClass().getSimpleName() + this.chunk.getPos(); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBlockStateWrapper getBlockState(int relX, int relY, int relZ)
|
|
||||||
{
|
|
||||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
|
|
||||||
|
|
||||||
BlockPos.MutableBlockPos blockPos = MUTABLE_BLOCK_POS_REF.get();
|
|
||||||
|
|
||||||
blockPos.setX(relX);
|
|
||||||
blockPos.setY(relY);
|
|
||||||
blockPos.setZ(relZ);
|
|
||||||
|
|
||||||
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; }
|
|
||||||
|
|
||||||
|
|
||||||
public static void syncedUpdateClientLightStatus()
|
public static void syncedUpdateClientLightStatus()
|
||||||
{
|
{
|
||||||
#if MC_VER < MC_1_18_2
|
#if MC_VER < MC_1_18_2
|
||||||
@@ -574,64 +556,57 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
//===============//
|
||||||
// helper methods //
|
// other methods //
|
||||||
//================//
|
//===============//
|
||||||
|
|
||||||
/** used to prevent accidentally attempting to get/set values outside this chunk's boundaries */
|
@Override
|
||||||
private void throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(int x, int y, int z) throws IndexOutOfBoundsException
|
public boolean doNearbyChunksExist()
|
||||||
{
|
{
|
||||||
if (!RUN_RELATIVE_POS_INDEX_VALIDATION)
|
if (this.lightSource instanceof DhLitWorldGenRegion)
|
||||||
{
|
{
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int dx = -1; dx <= 1; dx++)
|
||||||
// FIXME +1 is to handle the fact that LodDataBuilder adds +1 to all block lighting calculations, also done in the constructor
|
|
||||||
int minHeight = this.getMinBuildHeight();
|
|
||||||
int maxHeight = this.getMaxBuildHeight() + 1;
|
|
||||||
|
|
||||||
if (x < 0 || x >= LodUtil.CHUNK_WIDTH
|
|
||||||
|| z < 0 || z >= LodUtil.CHUNK_WIDTH
|
|
||||||
|| y < minHeight || y > maxHeight)
|
|
||||||
{
|
{
|
||||||
String errorMessage = "Relative position [" + x + "," + y + "," + z + "] out of bounds. \n" +
|
for (int dz = -1; dz <= 1; dz++)
|
||||||
"X/Z must be between 0 and 15 (inclusive) \n" +
|
{
|
||||||
"Y must be between [" + minHeight + "] and [" + maxHeight + "] (inclusive).";
|
if (dx == 0 && dz == 0)
|
||||||
throw new IndexOutOfBoundsException(errorMessage);
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (this.lightSource.getChunk(dx + this.chunk.getPos().x, dz + this.chunk.getPos().z, ChunkStatus.BIOMES, false) == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a 3D position into a 1D array index. <br><br>
|
|
||||||
*
|
|
||||||
* Source: <br>
|
|
||||||
* <a href="https://stackoverflow.com/questions/7367770/how-to-flatten-or-index-3d-array-in-1d-array">stackoverflow</a>
|
|
||||||
*/
|
|
||||||
public int relativeBlockPosToIndex(int xRel, int y, int zRel)
|
|
||||||
{
|
|
||||||
int yRel = y - this.getMinBuildHeight();
|
|
||||||
return (zRel * LodUtil.CHUNK_WIDTH * this.getHeight()) + (yRel * LodUtil.CHUNK_WIDTH) + xRel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a 3D position into a 1D array index. <br><br>
|
|
||||||
*
|
|
||||||
* Source: <br>
|
|
||||||
* <a href="https://stackoverflow.com/questions/7367770/how-to-flatten-or-index-3d-array-in-1d-array">stackoverflow</a>
|
|
||||||
*/
|
|
||||||
public DhBlockPos indexToRelativeBlockPos(int index)
|
|
||||||
{
|
|
||||||
final int zRel = index / (LodUtil.CHUNK_WIDTH * this.getHeight());
|
|
||||||
index -= (zRel * LodUtil.CHUNK_WIDTH * this.getHeight());
|
|
||||||
|
|
||||||
final int y = index / LodUtil.CHUNK_WIDTH;
|
//================//
|
||||||
final int yRel = y + this.getMinBuildHeight();
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
|
||||||
final int xRel = index % LodUtil.CHUNK_WIDTH;
|
@Override
|
||||||
return new DhBlockPos(xRel, yRel, zRel);
|
public String toString() { return this.chunk.getClass().getSimpleName() + this.chunk.getPos(); }
|
||||||
}
|
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
//public int hashCode()
|
||||||
|
//{
|
||||||
|
// if (this.blockBiomeHashCode == 0)
|
||||||
|
// {
|
||||||
|
// this.blockBiomeHashCode = this.getBlockBiomeHashCode();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return this.blockBiomeHashCode;
|
||||||
|
//}
|
||||||
|
|
||||||
}
|
}
|
||||||
+20
-9
@@ -158,19 +158,22 @@ public class ClassicConfigGUI
|
|||||||
// button.active = entries.stream().allMatch(e -> e.inLimits);
|
// button.active = entries.stream().allMatch(e -> e.inLimits);
|
||||||
|
|
||||||
|
|
||||||
if (((ConfigEntry) info).isValid(value) == 0 && info.getType() != List.class)
|
if (info.getType() == String.class
|
||||||
|
|| info.getType() == List.class)
|
||||||
|
{
|
||||||
|
((ConfigEntry) info).uiSetWithoutSaving(stringValue);
|
||||||
|
}
|
||||||
|
else if (((ConfigEntry) info).isValid(value) == 0)
|
||||||
{
|
{
|
||||||
if (!cast)
|
if (!cast)
|
||||||
|
{
|
||||||
((ConfigEntry) info).uiSetWithoutSaving(value);
|
((ConfigEntry) info).uiSetWithoutSaving(value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
((ConfigEntry) info).uiSetWithoutSaving(value.intValue());
|
((ConfigEntry) info).uiSetWithoutSaving(value.intValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// else if (((ConfigEntry) info).isValidMemoryAddress() == 0)
|
|
||||||
// {
|
|
||||||
// if (((List<String>) info.get()).size() == ((EntryInfo) info.guiValue).index)
|
|
||||||
// info.uiSet(((List<String>) info.get()).add(""));
|
|
||||||
// info.uiSet(((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;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -245,7 +248,7 @@ public class ClassicConfigGUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Changelog button
|
// Changelog button
|
||||||
if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() && Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE)
|
if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() && !ModInfo.IS_DEV_BUILD) // we only have changelogs for stable builds
|
||||||
{
|
{
|
||||||
this.addBtn(new TexturedButtonWidget(
|
this.addBtn(new TexturedButtonWidget(
|
||||||
// Where the button is on the screen
|
// Where the button is on the screen
|
||||||
@@ -255,7 +258,13 @@ public class ClassicConfigGUI
|
|||||||
// texture UV Offset
|
// texture UV Offset
|
||||||
0, 0,
|
0, 0,
|
||||||
// Some textuary stuff
|
// Some textuary stuff
|
||||||
0, new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"), 20, 20,
|
0,
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
|
||||||
|
#else
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
|
||||||
|
#endif
|
||||||
|
20, 20,
|
||||||
// Create the button and tell it where to go
|
// Create the button and tell it where to go
|
||||||
(buttonWidget) -> {
|
(buttonWidget) -> {
|
||||||
ChangelogScreen changelogScreen = new ChangelogScreen(this);
|
ChangelogScreen changelogScreen = new ChangelogScreen(this);
|
||||||
@@ -437,7 +446,9 @@ public class ClassicConfigGUI
|
|||||||
String key = translationPrefix + (newInfo.category.isEmpty() ? "" : newInfo.category + ".") + newInfo.getName() + ".@tooltip";
|
String key = translationPrefix + (newInfo.category.isEmpty() ? "" : newInfo.category + ".") + newInfo.getName() + ".@tooltip";
|
||||||
|
|
||||||
if (((EntryInfo) newInfo.guiValue).error != null && text.equals(name))
|
if (((EntryInfo) newInfo.guiValue).error != null && text.equals(name))
|
||||||
|
{
|
||||||
DhRenderTooltip(matrices, font, ((EntryInfo) newInfo.guiValue).error.getValue(), mouseX, mouseY);
|
DhRenderTooltip(matrices, font, ((EntryInfo) newInfo.guiValue).error.getValue(), mouseX, mouseY);
|
||||||
|
}
|
||||||
else if (I18n.exists(key) && (text != null && text.equals(name)))
|
else if (I18n.exists(key) && (text != null && text.equals(name)))
|
||||||
{
|
{
|
||||||
List<Component> list = new ArrayList<>();
|
List<Component> list = new ArrayList<>();
|
||||||
|
|||||||
+11
-6
@@ -101,11 +101,17 @@ public class ChangelogScreen extends DhScreen
|
|||||||
this.changelog.add("");
|
this.changelog.add("");
|
||||||
this.changelog.add("");
|
this.changelog.add("");
|
||||||
|
|
||||||
|
String changelog = ModrinthGetter.changeLogs.get(versionID);
|
||||||
|
if (changelog == null)
|
||||||
|
{
|
||||||
|
// in case something goes wrong this will prevent null pointers
|
||||||
|
changelog = "";
|
||||||
|
}
|
||||||
|
|
||||||
// Get the release changelog and split it by the new lines
|
// Get the release changelog and split it by the new lines
|
||||||
String[] unwrappedChangelog = // Arrays.asList could be used if a list object is desired here vs List.of which is only available for Java 9+
|
String[] unwrappedChangelog = // Arrays.asList could be used if a list object is desired here vs List.of which is only available for Java 9+
|
||||||
new MarkdownFormatter.MinecraftFormat().convertTo( // This formats markdown to minecraft's "§" characters
|
// This formats markdown to minecraft's "§" charactersnew MarkdownFormatter.MinecraftFormat().convertTo(
|
||||||
ModrinthGetter.changeLogs.get(versionID)
|
new MarkdownFormatter.MinecraftFormat().convertTo(changelog).split("\\n");
|
||||||
).split("\\n");
|
|
||||||
// Makes the words wrap around to not go off the screen
|
// Makes the words wrap around to not go off the screen
|
||||||
for (String str : unwrappedChangelog)
|
for (String str : unwrappedChangelog)
|
||||||
{
|
{
|
||||||
@@ -168,10 +174,9 @@ public class ChangelogScreen extends DhScreen
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
this.changelogArea.render(matrices, mouseX, mouseY, delta); // Render the changelog
|
// render order matters, otherwise on 1.20.6+ the blurred background will render on top of the text
|
||||||
|
|
||||||
super.render(matrices, mouseX, mouseY, delta); // Render the buttons
|
super.render(matrices, mouseX, mouseY, delta); // Render the buttons
|
||||||
|
this.changelogArea.render(matrices, mouseX, mouseY, delta); // Render the changelog
|
||||||
DhDrawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
|
DhDrawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
-12
@@ -42,15 +42,17 @@ public class UpdateModScreen extends DhScreen
|
|||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.newVersionID = newVersionID;
|
this.newVersionID = newVersionID;
|
||||||
|
|
||||||
switch (Config.Client.Advanced.AutoUpdater.updateBranch.get()) {
|
|
||||||
case STABLE:
|
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
|
||||||
currentVer = ModInfo.VERSION;
|
if (updateBranch == EDhApiUpdateBranch.STABLE)
|
||||||
nextVer = ModrinthGetter.releaseNames.get(this.newVersionID);
|
{
|
||||||
break;
|
this.currentVer = ModInfo.VERSION;
|
||||||
case NIGHTLY:
|
this.nextVer = ModrinthGetter.releaseNames.get(this.newVersionID);
|
||||||
currentVer = ModJarInfo.Git_Commit.substring(0,7);
|
}
|
||||||
nextVer = this.newVersionID.substring(0,7);
|
else
|
||||||
break;
|
{
|
||||||
|
this.currentVer = ModJarInfo.Git_Commit.substring(0,7);
|
||||||
|
this.nextVer = this.newVersionID.substring(0,7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +75,13 @@ public class UpdateModScreen extends DhScreen
|
|||||||
// Offset
|
// Offset
|
||||||
0, 0,
|
0, 0,
|
||||||
// Some textuary stuff
|
// Some textuary stuff
|
||||||
0, new ResourceLocation(ModInfo.ID, "logo.png"), 130, 65,
|
0,
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
new ResourceLocation(ModInfo.ID, "logo.png"),
|
||||||
|
#else
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "logo.png"),
|
||||||
|
#endif
|
||||||
|
130, 65,
|
||||||
// Create the button and tell it where to go
|
// Create the button and tell it where to go
|
||||||
// For now it goes to the client option by default
|
// 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)
|
(buttonWidget) -> System.out.println("Nice, you found an easter egg :)"), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
|
||||||
@@ -88,7 +96,7 @@ public class UpdateModScreen extends DhScreen
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE)
|
if (!ModInfo.IS_DEV_BUILD)
|
||||||
{
|
{
|
||||||
this.addBtn(new TexturedButtonWidget(
|
this.addBtn(new TexturedButtonWidget(
|
||||||
// Where the button is on the screen
|
// Where the button is on the screen
|
||||||
@@ -98,7 +106,13 @@ public class UpdateModScreen extends DhScreen
|
|||||||
// Offset
|
// Offset
|
||||||
0, 0,
|
0, 0,
|
||||||
// Some textuary stuff
|
// Some textuary stuff
|
||||||
0, new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"), 20, 20,
|
0,
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
|
||||||
|
#else
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
|
||||||
|
#endif
|
||||||
|
20, 20,
|
||||||
// Create the button and tell it where to go
|
// Create the button and tell it where to go
|
||||||
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(new ChangelogScreen(this, this.newVersionID)), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
|
(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
|
// Add a title to the button
|
||||||
|
|||||||
+30
-17
@@ -1,21 +1,20 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers.level;
|
package com.seibel.distanthorizons.common.wrappers.level;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
|
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
|
||||||
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager;
|
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class KeyedClientLevelManager implements IKeyedClientLevelManager
|
public class KeyedClientLevelManager implements IKeyedClientLevelManager
|
||||||
{
|
{
|
||||||
public static final KeyedClientLevelManager INSTANCE = new KeyedClientLevelManager();
|
public static final KeyedClientLevelManager INSTANCE = new KeyedClientLevelManager();
|
||||||
|
|
||||||
/** This is set and managed by the ClientApi for servers with support for DH. */
|
/** This is set and managed by the ClientApi for servers with support for DH. */
|
||||||
private IServerKeyedClientLevel overrideWrapper = null;
|
@Nullable
|
||||||
private boolean useOverrideWrapper = false;
|
private IServerKeyedClientLevel serverKeyedLevel = null;
|
||||||
|
private boolean enabled = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=============//
|
//=============//
|
||||||
@@ -30,25 +29,39 @@ public class KeyedClientLevelManager implements IKeyedClientLevelManager
|
|||||||
// level override logic //
|
// level override logic //
|
||||||
//======================//
|
//======================//
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setServerKeyedLevel(IServerKeyedClientLevel clientLevel) { this.overrideWrapper = clientLevel; }
|
|
||||||
@Override
|
|
||||||
public IServerKeyedClientLevel getOverrideWrapper() { return this.overrideWrapper; }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IServerKeyedClientLevel getServerKeyedLevel(ILevelWrapper level, String serverLevelKey)
|
@Nullable
|
||||||
|
public IServerKeyedClientLevel getServerKeyedLevel()
|
||||||
{
|
{
|
||||||
Objects.requireNonNull(level);
|
return this.serverKeyedLevel;
|
||||||
Objects.requireNonNull(serverLevelKey);
|
|
||||||
return new ServerKeyedClientLevel((ClientLevel) level.getWrappedMcObject(), serverLevelKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String levelKey)
|
||||||
|
{
|
||||||
|
IServerKeyedClientLevel keyedLevel = new ServerKeyedClientLevel((ClientLevel) clientLevel.getWrappedMcObject(), levelKey);
|
||||||
|
this.serverKeyedLevel = keyedLevel;
|
||||||
|
this.enabled = true;
|
||||||
|
return keyedLevel;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUseOverrideWrapper(boolean useOverrideWrapper) { this.useOverrideWrapper = useOverrideWrapper; }
|
public void clearServerKeyedLevel()
|
||||||
|
{
|
||||||
|
this.serverKeyedLevel = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getUseOverrideWrapper() { return this.useOverrideWrapper; }
|
public boolean isEnabled()
|
||||||
|
{
|
||||||
|
return this.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disable()
|
||||||
|
{
|
||||||
|
this.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -18,4 +18,11 @@ public class ServerKeyedClientLevel extends ClientLevelWrapper implements IServe
|
|||||||
@Override
|
@Override
|
||||||
public String getServerLevelKey() { return this.serverLevelKey; }
|
public String getServerLevelKey() { return this.serverLevelKey; }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDimensionName()
|
||||||
|
{
|
||||||
|
return this.getServerLevelKey();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+84
-69
@@ -31,6 +31,7 @@ import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
|||||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||||
|
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
@@ -38,13 +39,14 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftCli
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||||
|
|
||||||
import net.minecraft.CrashReport;
|
import net.minecraft.CrashReport;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
import net.minecraft.client.multiplayer.ServerData;
|
||||||
import net.minecraft.client.player.LocalPlayer;
|
import net.minecraft.client.player.LocalPlayer;
|
||||||
import net.minecraft.client.resources.model.ModelManager;
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
@@ -52,6 +54,7 @@ import net.minecraft.network.chat.TextComponent;
|
|||||||
#endif
|
#endif
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@@ -59,16 +62,15 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
* A singleton that wraps the Minecraft object.
|
* A singleton that wraps the Minecraft object.
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 3-5-2022
|
|
||||||
*/
|
*/
|
||||||
//@Environment(EnvType.CLIENT)
|
|
||||||
public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecraftSharedWrapper
|
public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecraftSharedWrapper
|
||||||
{
|
{
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||||
|
private static final Minecraft MINECRAFT = Minecraft.getInstance();
|
||||||
|
|
||||||
public static final MinecraftClientWrapper INSTANCE = new MinecraftClientWrapper();
|
public static final MinecraftClientWrapper INSTANCE = new MinecraftClientWrapper();
|
||||||
|
|
||||||
public final Minecraft mc = Minecraft.getInstance();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The lightmap for the current:
|
* The lightmap for the current:
|
||||||
@@ -99,10 +101,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
|||||||
* This doesn't affect OpenGL objects in any way.
|
* This doesn't affect OpenGL objects in any way.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void clearFrameObjectCache()
|
public void clearFrameObjectCache() { this.lightMap = null; }
|
||||||
{
|
|
||||||
lightMap = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -118,10 +117,10 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
|||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case AUTO:
|
case AUTO:
|
||||||
if (this.mc.level != null)
|
if (MINECRAFT.level != null)
|
||||||
{
|
{
|
||||||
Direction mcDir = McObjectConverter.Convert(lodDirection);
|
Direction mcDir = McObjectConverter.Convert(lodDirection);
|
||||||
return this.mc.level.getShade(mcDir, true);
|
return MINECRAFT.level.getShade(mcDir, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -150,47 +149,63 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasSinglePlayerServer() { return mc.hasSingleplayerServer(); }
|
public boolean hasSinglePlayerServer() { return MINECRAFT.hasSingleplayerServer(); }
|
||||||
@Override
|
@Override
|
||||||
public boolean clientConnectedToDedicatedServer() { return mc.getCurrentServer() != null && !this.hasSinglePlayerServer(); }
|
public boolean clientConnectedToDedicatedServer() { return MINECRAFT.getCurrentServer() != null && !this.hasSinglePlayerServer(); }
|
||||||
|
@Override
|
||||||
|
public boolean connectedToReplay() { return !MINECRAFT.hasSingleplayerServer() && MINECRAFT.getCurrentServer() == null; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCurrentServerName() { return mc.getCurrentServer().name; }
|
public String getCurrentServerName()
|
||||||
|
{
|
||||||
|
if (this.connectedToReplay())
|
||||||
|
{
|
||||||
|
return ClientOnlySaveStructure.REPLAY_SERVER_FOLDER_NAME;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ServerData server = MINECRAFT.getCurrentServer();
|
||||||
|
return (server != null) ? server.name : "NULL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCurrentServerIp() { return mc.getCurrentServer().ip; }
|
public String getCurrentServerIp()
|
||||||
|
{
|
||||||
|
if (this.connectedToReplay())
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ServerData server = MINECRAFT.getCurrentServer();
|
||||||
|
return (server != null) ? server.ip : "NA";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCurrentServerVersion()
|
public String getCurrentServerVersion()
|
||||||
{
|
{
|
||||||
return mc.getCurrentServer().version.getString();
|
ServerData server = MINECRAFT.getCurrentServer();
|
||||||
|
return (server != null) ? server.version.getString() : "UNKOWN";
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============//
|
//=============//
|
||||||
// Simple gets //
|
// Simple gets //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public LocalPlayer getPlayer()
|
public LocalPlayer getPlayer() { return MINECRAFT.player; }
|
||||||
{
|
|
||||||
return mc.player;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean playerExists()
|
public boolean playerExists() { return MINECRAFT.player != null; }
|
||||||
{
|
|
||||||
return mc.player != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID getPlayerUUID()
|
public UUID getPlayerUUID() { return this.getPlayer().getUUID(); }
|
||||||
{
|
|
||||||
return getPlayer().getUUID();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DhBlockPos getPlayerBlockPos()
|
public DhBlockPos getPlayerBlockPos()
|
||||||
{
|
{
|
||||||
BlockPos playerPos = getPlayer().blockPosition();
|
BlockPos playerPos = this.getPlayer().blockPosition();
|
||||||
return new DhBlockPos(playerPos.getX(), playerPos.getY(), playerPos.getZ());
|
return new DhBlockPos(playerPos.getX(), playerPos.getY(), playerPos.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,46 +213,46 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
|||||||
public DhChunkPos getPlayerChunkPos()
|
public DhChunkPos getPlayerChunkPos()
|
||||||
{
|
{
|
||||||
#if MC_VER < MC_1_17_1
|
#if MC_VER < MC_1_17_1
|
||||||
ChunkPos playerPos = new ChunkPos(getPlayer().blockPosition());
|
ChunkPos playerPos = new ChunkPos(this.getPlayer().blockPosition());
|
||||||
#else
|
#else
|
||||||
ChunkPos playerPos = getPlayer().chunkPosition();
|
ChunkPos playerPos = this.getPlayer().chunkPosition();
|
||||||
#endif
|
#endif
|
||||||
return new DhChunkPos(playerPos.x, playerPos.z);
|
return new DhChunkPos(playerPos.x, playerPos.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModelManager getModelManager()
|
|
||||||
{
|
|
||||||
return mc.getModelManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public IClientLevelWrapper getWrappedClientLevel()
|
public IClientLevelWrapper getWrappedClientLevel()
|
||||||
{
|
{
|
||||||
if (this.mc.level == null)
|
return this.getWrappedClientLevel(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public IClientLevelWrapper getWrappedClientLevel(boolean bypassMultiverse)
|
||||||
|
{
|
||||||
|
ClientLevel level = MINECRAFT.level;
|
||||||
|
if (level == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ClientLevelWrapper.getWrapperIgnoringOverride(this.mc.level);
|
return ClientLevelWrapper.getWrapper(level, bypassMultiverse);
|
||||||
}
|
|
||||||
|
|
||||||
/** Please move over to getInstallationDirectory() */
|
|
||||||
@Deprecated
|
|
||||||
@Override
|
|
||||||
public File getGameDirectory()
|
|
||||||
{
|
|
||||||
return getInstallationDirectory();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IProfilerWrapper getProfiler()
|
public IProfilerWrapper getProfiler()
|
||||||
{
|
{
|
||||||
if (profilerWrapper == null)
|
if (this.profilerWrapper == null)
|
||||||
profilerWrapper = new ProfilerWrapper(mc.getProfiler());
|
{
|
||||||
else if (mc.getProfiler() != profilerWrapper.profiler)
|
this.profilerWrapper = new ProfilerWrapper(MINECRAFT.getProfiler());
|
||||||
profilerWrapper.profiler = mc.getProfiler();
|
}
|
||||||
return profilerWrapper;
|
else if (MINECRAFT.getProfiler() != this.profilerWrapper.profiler)
|
||||||
|
{
|
||||||
|
this.profilerWrapper.profiler = MINECRAFT.getProfiler();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.profilerWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns all worlds available to the server */
|
/** Returns all worlds available to the server */
|
||||||
@@ -246,7 +261,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
|||||||
{
|
{
|
||||||
ArrayList<ILevelWrapper> worlds = new ArrayList<ILevelWrapper>();
|
ArrayList<ILevelWrapper> worlds = new ArrayList<ILevelWrapper>();
|
||||||
|
|
||||||
Iterable<ServerLevel> serverWorlds = mc.getSingleplayerServer().getAllLevels();
|
Iterable<ServerLevel> serverWorlds = MINECRAFT.getSingleplayerServer().getAllLevels();
|
||||||
for (ServerLevel world : serverWorlds)
|
for (ServerLevel world : serverWorlds)
|
||||||
{
|
{
|
||||||
worlds.add(ServerLevelWrapper.getWrapper(world));
|
worlds.add(ServerLevelWrapper.getWrapper(world));
|
||||||
@@ -260,12 +275,15 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
|||||||
@Override
|
@Override
|
||||||
public void sendChatMessage(String string)
|
public void sendChatMessage(String string)
|
||||||
{
|
{
|
||||||
LocalPlayer p = getPlayer();
|
LocalPlayer player = this.getPlayer();
|
||||||
if (p == null) return;
|
if (player == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
p.sendMessage(new TextComponent(string), getPlayer().getUUID());
|
player.sendMessage(new TextComponent(string), getPlayer().getUUID());
|
||||||
#else
|
#else
|
||||||
p.sendSystemMessage(net.minecraft.network.chat.Component.translatable(string));
|
player.sendSystemMessage(net.minecraft.network.chat.Component.translatable(string));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,24 +308,21 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getOptionsObject()
|
public Object getOptionsObject() { return MINECRAFT.options; }
|
||||||
{
|
|
||||||
return mc.options;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDedicatedServer()
|
public boolean isDedicatedServer() { return false; }
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getInstallationDirectory()
|
public File getInstallationDirectory() { return MINECRAFT.gameDirectory; }
|
||||||
{
|
|
||||||
return mc.gameDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeOnRenderThread(Runnable runnable) { this.mc.execute(runnable); }
|
public void executeOnRenderThread(Runnable runnable) { MINECRAFT.execute(runnable); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWorldInitialized()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("TODO");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-6
@@ -12,16 +12,26 @@ public class MinecraftDedicatedServerWrapper implements IMinecraftSharedWrapper
|
|||||||
private MinecraftDedicatedServerWrapper() { }
|
private MinecraftDedicatedServerWrapper() { }
|
||||||
public DedicatedServer dedicatedServer = null;
|
public DedicatedServer dedicatedServer = null;
|
||||||
@Override
|
@Override
|
||||||
public boolean isDedicatedServer()
|
public boolean isDedicatedServer() { return true; }
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public File getInstallationDirectory()
|
public File getInstallationDirectory()
|
||||||
{
|
{
|
||||||
if (dedicatedServer == null)
|
if (this.dedicatedServer == null)
|
||||||
|
{
|
||||||
throw new IllegalStateException("Trying to get Installation Direction before Dedicated server complete initialization!");
|
throw new IllegalStateException("Trying to get Installation Direction before Dedicated server complete initialization!");
|
||||||
return dedicatedServer.getServerDirectory();
|
}
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
return this.dedicatedServer.getServerDirectory();
|
||||||
|
#else
|
||||||
|
return this.dedicatedServer.getServerDirectory().toFile();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWorldInitialized()
|
||||||
|
{
|
||||||
|
return this.dedicatedServer.getWorldData().overworldData().isInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+21
-141
@@ -21,31 +21,26 @@ package com.seibel.distanthorizons.common.wrappers.minecraft;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.pipeline.RenderTarget;
|
import com.mojang.blaze3d.pipeline.RenderTarget;
|
||||||
import com.mojang.blaze3d.platform.NativeImage;
|
import com.mojang.blaze3d.platform.NativeImage;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.WrapperFactory;
|
import com.seibel.distanthorizons.common.wrappers.WrapperFactory;
|
||||||
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
|
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
|
||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_17_1
|
||||||
|
import net.minecraft.client.renderer.FogRenderer;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_4
|
#if MC_VER < MC_1_19_4
|
||||||
import org.joml.Vector3f;
|
|
||||||
#else
|
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
#else
|
||||||
#endif
|
#endif
|
||||||
#if MC_VER >= MC_1_20_2
|
#if MC_VER >= MC_1_20_2
|
||||||
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
|
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
|
||||||
@@ -55,20 +50,14 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOpt
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||||
import com.seibel.distanthorizons.coreapi.util.math.Vec3d;
|
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||||
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
|
||||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
|
||||||
|
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.FogRenderer;
|
|
||||||
import net.minecraft.client.renderer.LevelRenderer;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.world.effect.MobEffects;
|
import net.minecraft.world.effect.MobEffects;
|
||||||
#if MC_VER < MC_1_17_1
|
#if MC_VER < MC_1_17_1
|
||||||
import net.minecraft.tags.FluidTags;
|
import net.minecraft.tags.FluidTags;
|
||||||
@@ -78,10 +67,8 @@ import org.lwjgl.opengl.GL15;
|
|||||||
#else
|
#else
|
||||||
import net.minecraft.world.level.material.FogType;
|
import net.minecraft.world.level.material.FogType;
|
||||||
#endif
|
#endif
|
||||||
import net.minecraft.world.phys.AABB;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.joml.Matrix4f;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,14 +110,6 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
|||||||
return new Vec3f(camera.getLookVector().x(), camera.getLookVector().y(), camera.getLookVector().z());
|
return new Vec3f(camera.getLookVector().x(), camera.getLookVector().y(), camera.getLookVector().z());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DhBlockPos getCameraBlockPosition()
|
|
||||||
{
|
|
||||||
Camera camera = MC.gameRenderer.getMainCamera();
|
|
||||||
BlockPos blockPos = camera.getBlockPosition();
|
|
||||||
return new DhBlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
/** Unless you really need to know if the player is blind, use {@link MinecraftRenderWrapper#isFogStateSpecial()}/{@link IMinecraftRenderWrapper#isFogStateSpecial()} instead */
|
/** Unless you really need to know if the player is blind, use {@link MinecraftRenderWrapper#isFogStateSpecial()}/{@link IMinecraftRenderWrapper#isFogStateSpecial()} instead */
|
||||||
public boolean playerHasBlindingEffect()
|
public boolean playerHasBlindingEffect()
|
||||||
@@ -151,43 +130,6 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
|||||||
return new Vec3d(projectedView.x, projectedView.y, projectedView.z);
|
return new Vec3d(projectedView.x, projectedView.y, projectedView.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Mat4f getWorldViewMatrix()
|
|
||||||
{
|
|
||||||
Camera camera = MC.gameRenderer.getMainCamera();
|
|
||||||
Vector3f cameraVec3 = new Vector3f(
|
|
||||||
(float)camera.getPosition().x,
|
|
||||||
(float)camera.getPosition().y,
|
|
||||||
(float)camera.getPosition().z);
|
|
||||||
cameraVec3 = cameraVec3.negate();
|
|
||||||
|
|
||||||
Matrix4f matWorldView = new Matrix4f()
|
|
||||||
.rotateX((float)Math.toRadians(camera.getXRot()))
|
|
||||||
.rotateY((float)Math.toRadians(camera.getYRot() + 180f))
|
|
||||||
.translate(cameraVec3);
|
|
||||||
return new Mat4f(matWorldView);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Mat4f getDefaultProjectionMatrix(float partialTicks)
|
|
||||||
{
|
|
||||||
#if MC_VER < 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
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getGamma()
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_19_2
|
|
||||||
return MC.options.gamma;
|
|
||||||
#else
|
|
||||||
return MC.options.gamma().get();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Color getFogColor(float partialTicks)
|
public Color getFogColor(float partialTicks)
|
||||||
{
|
{
|
||||||
@@ -212,15 +154,24 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
|||||||
{
|
{
|
||||||
if (MC.level.dimensionType().hasSkyLight())
|
if (MC.level.dimensionType().hasSkyLight())
|
||||||
{
|
{
|
||||||
#if MC_VER < MC_1_17_1
|
float frameTime;
|
||||||
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getBlockPosition(), MC.getFrameTime());
|
#if MC_VER < MC_1_21_1
|
||||||
|
frameTime = MC.getFrameTime();
|
||||||
#else
|
#else
|
||||||
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), MC.getFrameTime());
|
frameTime = MC.getTimer().getRealtimeDeltaTicks();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_17_1
|
||||||
|
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getBlockPosition(), frameTime);
|
||||||
|
#else
|
||||||
|
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);
|
||||||
#endif
|
#endif
|
||||||
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
|
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return new Color(0, 0, 0);
|
return new Color(0, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -308,77 +259,6 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
|||||||
return getRenderTarget().viewHeight;
|
return getRenderTarget().viewHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the ChunkPos of all chunks that Minecraft
|
|
||||||
* is going to render this frame. <br><br>
|
|
||||||
* <p>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean usingBackupGetVanillaRenderedChunks = false;
|
|
||||||
@Override
|
|
||||||
public HashSet<DhChunkPos> getVanillaRenderedChunks()
|
|
||||||
{
|
|
||||||
ISodiumAccessor sodium = ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class);
|
|
||||||
if (sodium != null)
|
|
||||||
{
|
|
||||||
return sodium.getNormalRenderedChunks();
|
|
||||||
}
|
|
||||||
IOptifineAccessor optifine = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
|
|
||||||
if (optifine != null)
|
|
||||||
{
|
|
||||||
HashSet<DhChunkPos> pos = optifine.getNormalRenderedChunks();
|
|
||||||
if (pos == null)
|
|
||||||
pos = getMaximumRenderedChunks();
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
if (!usingBackupGetVanillaRenderedChunks)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_20_2
|
|
||||||
LevelRenderer levelRenderer = MC.levelRenderer;
|
|
||||||
Collection<LevelRenderer.RenderChunkInfo> chunks =
|
|
||||||
#if MC_VER < MC_1_18_2 levelRenderer.renderChunks;
|
|
||||||
#else levelRenderer.renderChunkStorage.get().renderChunks; #endif
|
|
||||||
|
|
||||||
return (chunks.stream().map((chunk) -> {
|
|
||||||
AABB chunkBoundingBox =
|
|
||||||
#if MC_VER < MC_1_18_2 chunk.chunk.bb;
|
|
||||||
#else chunk.chunk.getBoundingBox(); #endif
|
|
||||||
return new DhChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
|
|
||||||
Math.floorDiv((int) chunkBoundingBox.minZ, 16));
|
|
||||||
}).collect(Collectors.toCollection(HashSet::new)));
|
|
||||||
#else
|
|
||||||
LevelRenderer levelRenderer = MC.levelRenderer;
|
|
||||||
Collection<SectionRenderDispatcher.RenderSection> chunks = levelRenderer.visibleSections;
|
|
||||||
|
|
||||||
return (chunks.stream().map((chunk) -> {
|
|
||||||
AABB chunkBoundingBox = chunk.getBoundingBox();
|
|
||||||
return new DhChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
|
|
||||||
Math.floorDiv((int) chunkBoundingBox.minZ, 16));
|
|
||||||
}).collect(Collectors.toCollection(HashSet::new)));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
catch (LinkageError e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
MinecraftClientWrapper.INSTANCE.sendChatMessage(
|
|
||||||
"\u00A7e\u00A7l\u00A7uWARNING: Distant Horizons: getVanillaRenderedChunks method failed."
|
|
||||||
+ " Using Backup Method.");
|
|
||||||
MinecraftClientWrapper.INSTANCE.sendChatMessage(
|
|
||||||
"\u00A7eOverdraw prevention will be worse than normal.");
|
|
||||||
}
|
|
||||||
catch (Exception e2)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
LOGGER.error("getVanillaRenderedChunks Error: ", e);
|
|
||||||
usingBackupGetVanillaRenderedChunks = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return getMaximumRenderedChunks();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ILightMapWrapper getLightmapWrapper(ILevelWrapper level) { return this.lightmapByDimensionType.get(level.getDimensionType()); }
|
public ILightMapWrapper getLightmapWrapper(ILevelWrapper level) { return this.lightmapByDimensionType.get(level.getDimensionType()); }
|
||||||
|
|
||||||
@@ -406,7 +286,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
|||||||
// so this will have to do for now
|
// so this will have to do for now
|
||||||
IDimensionTypeWrapper dimensionType = level.getDimensionType();
|
IDimensionTypeWrapper dimensionType = level.getDimensionType();
|
||||||
|
|
||||||
LightMapWrapper wrapper = this.lightmapByDimensionType.compute(dimensionType, (dimType, oldWrapper) -> new LightMapWrapper());
|
LightMapWrapper wrapper = this.lightmapByDimensionType.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper());
|
||||||
wrapper.uploadLightmap(lightPixels);
|
wrapper.uploadLightmap(lightPixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package com.seibel.distanthorizons.common.wrappers.misc;
|
||||||
|
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public interface IMixinServerPlayer
|
||||||
|
{
|
||||||
|
@Nullable
|
||||||
|
ServerLevel distantHorizons$getDimensionChangeDestination();
|
||||||
|
|
||||||
|
}
|
||||||
+12
-9
@@ -36,14 +36,6 @@ public class LightMapWrapper implements ILightMapWrapper
|
|||||||
|
|
||||||
public LightMapWrapper() { }
|
public LightMapWrapper() { }
|
||||||
|
|
||||||
private void createLightmap(NativeImage image)
|
|
||||||
{
|
|
||||||
this.textureId = GL32.glGenTextures();
|
|
||||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=========//
|
//=========//
|
||||||
@@ -53,14 +45,25 @@ public class LightMapWrapper implements ILightMapWrapper
|
|||||||
public void uploadLightmap(NativeImage image)
|
public void uploadLightmap(NativeImage image)
|
||||||
{
|
{
|
||||||
int currentBind = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
|
int currentBind = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
|
||||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.textureId);
|
|
||||||
if (this.textureId == 0)
|
if (this.textureId == 0)
|
||||||
{
|
{
|
||||||
this.createLightmap(image);
|
this.createLightmap(image);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.textureId);
|
||||||
|
}
|
||||||
image.upload(0, 0, 0, false);
|
image.upload(0, 0, 0, false);
|
||||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, currentBind);
|
GL32.glBindTexture(GL32.GL_TEXTURE_2D, currentBind);
|
||||||
}
|
}
|
||||||
|
private void createLightmap(NativeImage image)
|
||||||
|
{
|
||||||
|
this.textureId = GL32.glGenTextures();
|
||||||
|
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bind()
|
public void bind()
|
||||||
|
|||||||
+81
-15
@@ -1,54 +1,120 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers.misc;
|
package com.seibel.distanthorizons.common.wrappers.misc;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.collect.MapMaker;
|
import com.google.common.collect.MapMaker;
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.net.SocketAddress;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This wrapper transparently ensures that underlying {@link ServerPlayer} is always valid,
|
||||||
|
* unless the player has disconnected.
|
||||||
|
*/
|
||||||
public class ServerPlayerWrapper implements IServerPlayerWrapper
|
public class ServerPlayerWrapper implements IServerPlayerWrapper
|
||||||
{
|
{
|
||||||
private static final ConcurrentMap<ServerPlayer, ServerPlayerWrapper>
|
private static final ConcurrentMap<ServerGamePacketListenerImpl, ServerPlayerWrapper> serverPlayerWrapperMap = new MapMaker().weakKeys().weakValues().makeMap();
|
||||||
serverPlayerWrapperMap = new MapMaker().weakKeys().makeMap();
|
|
||||||
|
|
||||||
private final ServerPlayer serverPlayer;
|
private final ServerGamePacketListenerImpl connection;
|
||||||
|
private ServerPlayer serverPlayer()
|
||||||
|
{
|
||||||
|
return this.connection.player;
|
||||||
|
}
|
||||||
|
|
||||||
public static ServerPlayerWrapper getWrapper(ServerPlayer serverPlayer)
|
public static ServerPlayerWrapper getWrapper(ServerPlayer serverPlayer)
|
||||||
{
|
{
|
||||||
return serverPlayerWrapperMap.computeIfAbsent(serverPlayer, ServerPlayerWrapper::new);
|
return serverPlayerWrapperMap.computeIfAbsent(serverPlayer.connection, ignored -> new ServerPlayerWrapper(serverPlayer.connection));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServerPlayerWrapper(ServerPlayer serverPlayer)
|
private ServerPlayerWrapper(ServerGamePacketListenerImpl connection)
|
||||||
{
|
{
|
||||||
this.serverPlayer = serverPlayer;
|
this.connection = connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getUUID()
|
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
{
|
{
|
||||||
return serverPlayer.getUUID();
|
return this.serverPlayer().getName().getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public IServerLevelWrapper getLevel()
|
public IServerLevelWrapper getLevel()
|
||||||
{
|
{
|
||||||
#if MC_VER < MC_1_20_1
|
ServerLevel level = ((IMixinServerPlayer) this.serverPlayer()).distantHorizons$getDimensionChangeDestination();
|
||||||
return ServerLevelWrapper.getWrapper(this.serverPlayer.getLevel());
|
if (level == null)
|
||||||
#else
|
{
|
||||||
return ServerLevelWrapper.getWrapper(this.serverPlayer.serverLevel());
|
#if MC_VER < MC_1_20_1
|
||||||
|
level = this.serverPlayer().getLevel();
|
||||||
|
#else
|
||||||
|
level = this.serverPlayer().serverLevel();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return ServerLevelWrapper.getWrapper(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vec3d getPosition()
|
||||||
|
{
|
||||||
|
Vec3 position = this.serverPlayer().position();
|
||||||
|
return new Vec3d(position.x, position.y, position.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getViewDistance()
|
||||||
|
{
|
||||||
|
return this.serverPlayer().server.getPlayerList().getViewDistance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SocketAddress getRemoteAddress()
|
||||||
|
{
|
||||||
|
#if MC_VER >= MC_1_19_4
|
||||||
|
return this.serverPlayer().connection.getRemoteAddress();
|
||||||
|
#else // < 1.19.4
|
||||||
|
return this.serverPlayer().connection.connection.getRemoteAddress();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Object getWrappedMcObject()
|
public Object getWrappedMcObject()
|
||||||
{
|
{
|
||||||
return serverPlayer;
|
return this.serverPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return "Wrapped{" + serverPlayer.toString() + "}";
|
return "Wrapped{" + this.serverPlayer() + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o)
|
||||||
|
{
|
||||||
|
if (this == o)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof ServerPlayerWrapper))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ServerPlayerWrapper that = (ServerPlayerWrapper) o;
|
||||||
|
return Objects.equal(this.connection, that.connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return Objects.hashCode(this.connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+99
-36
@@ -1,17 +1,17 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers.world;
|
package com.seibel.distanthorizons.common.wrappers.world;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
|
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
|
||||||
import com.seibel.distanthorizons.api.interfaces.world.IDhApiDimensionTypeWrapper;
|
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
|
||||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.cache.ClientBlockDetailMap;
|
import com.seibel.distanthorizons.common.wrappers.block.ClientBlockStateColorCache;
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager;
|
import com.seibel.distanthorizons.core.level.*;
|
||||||
|
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
@@ -19,16 +19,18 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.LightLayer;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkSource;
|
import net.minecraft.world.level.chunk.ChunkSource;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@@ -41,14 +43,18 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
|
|||||||
public class ClientLevelWrapper implements IClientLevelWrapper
|
public class ClientLevelWrapper implements IClientLevelWrapper
|
||||||
{
|
{
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(ClientLevelWrapper.class.getSimpleName());
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger(ClientLevelWrapper.class.getSimpleName());
|
||||||
private static final ConcurrentHashMap<ClientLevel, ClientLevelWrapper> LEVEL_WRAPPER_BY_CLIENT_LEVEL = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<ClientLevel, ClientLevelWrapper> LEVEL_WRAPPER_BY_CLIENT_LEVEL = new ConcurrentHashMap<>(); // TODO can leak
|
||||||
private static final IKeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = SingletonInjector.INSTANCE.get(IKeyedClientLevelManager.class);
|
private static final IKeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = SingletonInjector.INSTANCE.get(IKeyedClientLevelManager.class);
|
||||||
|
|
||||||
|
private static final Minecraft MINECRAFT = Minecraft.getInstance();
|
||||||
|
|
||||||
private final ClientLevel level;
|
private final ClientLevel level;
|
||||||
private final ClientBlockDetailMap blockMap = new ClientBlockDetailMap(this);
|
private final ConcurrentHashMap<BlockState, ClientBlockStateColorCache> blockCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private BlockStateWrapper dirtBlockWrapper;
|
private BlockStateWrapper dirtBlockWrapper;
|
||||||
private BiomeWrapper plainsBiomeWrapper;
|
private BiomeWrapper plainsBiomeWrapper;
|
||||||
|
@Deprecated // TODO circular references are bad
|
||||||
|
private IDhLevel parentDhLevel;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -64,23 +70,31 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
|||||||
// wrapper logic //
|
// wrapper logic //
|
||||||
//===============//
|
//===============//
|
||||||
|
|
||||||
@Nullable
|
public static IClientLevelWrapper getWrapper(@NotNull ClientLevel level)
|
||||||
public static IClientLevelWrapper getWrapper(@Nullable ClientLevel level)
|
|
||||||
{
|
{
|
||||||
if (level == null)
|
return getWrapper(level, false);
|
||||||
{
|
}
|
||||||
return null;
|
|
||||||
}
|
@Nullable
|
||||||
|
public static IClientLevelWrapper getWrapper(@Nullable ClientLevel level, boolean bypassLevelKeyManager)
|
||||||
// used if the client is connected to a server that defines the currently loaded level
|
{
|
||||||
if (KEYED_CLIENT_LEVEL_MANAGER.getUseOverrideWrapper())
|
if (!bypassLevelKeyManager)
|
||||||
{
|
{
|
||||||
return KEYED_CLIENT_LEVEL_MANAGER.getOverrideWrapper();
|
if (level == null)
|
||||||
}
|
{
|
||||||
|
return null;
|
||||||
return getWrapperIgnoringOverride(level);
|
}
|
||||||
|
|
||||||
|
// used if the client is connected to a server that defines the currently loaded level
|
||||||
|
IServerKeyedClientLevel overrideLevel = KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel();
|
||||||
|
if (overrideLevel != null)
|
||||||
|
{
|
||||||
|
return overrideLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return LEVEL_WRAPPER_BY_CLIENT_LEVEL.computeIfAbsent(level, ClientLevelWrapper::new);
|
||||||
}
|
}
|
||||||
public static IClientLevelWrapper getWrapperIgnoringOverride(@NotNull ClientLevel level) { return LEVEL_WRAPPER_BY_CLIENT_LEVEL.computeIfAbsent(level, ClientLevelWrapper::new); }
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
@@ -88,7 +102,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Iterable<ServerLevel> serverLevels = MinecraftClientWrapper.INSTANCE.mc.getSingleplayerServer().getAllLevels();
|
Iterable<ServerLevel> serverLevels = MINECRAFT.getSingleplayerServer().getAllLevels();
|
||||||
|
|
||||||
// attempt to find the server level with the same dimension type
|
// attempt to find the server level with the same dimension type
|
||||||
// TODO this assumes only one level per dimension type, the SubDimensionLevelMatcher will need to be added for supporting multiple levels per dimension
|
// TODO this assumes only one level per dimension type, the SubDimensionLevelMatcher will need to be added for supporting multiple levels per dimension
|
||||||
@@ -108,21 +122,23 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
LOGGER.error("Failed to get server side wrapper for client level: " + level);
|
LOGGER.error("Failed to get server side wrapper for client level: " + this.level);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//====================//
|
//====================//
|
||||||
// base level methods //
|
// base level methods //
|
||||||
//====================//
|
//====================//
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockState)
|
public int getBlockColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockWrapper)
|
||||||
{
|
{
|
||||||
return this.blockMap.getColor(((BlockStateWrapper) blockState).blockState, (BiomeWrapper) biome, pos);
|
ClientBlockStateColorCache blockColorCache = this.blockCache.computeIfAbsent(
|
||||||
|
((BlockStateWrapper) blockWrapper).blockState,
|
||||||
|
(block) -> new ClientBlockStateColorCache(block, this));
|
||||||
|
|
||||||
|
return blockColorCache.getColor((BiomeWrapper) biome, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -142,9 +158,12 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.blockMap.getColor(this.dirtBlockWrapper.blockState, BiomeWrapper.EMPTY_WRAPPER, DhBlockPos.ZERO);
|
return this.getBlockColor(DhBlockPos.ZERO,BiomeWrapper.EMPTY_WRAPPER, this.dirtBlockWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearBlockColorCache() { this.blockCache.clear(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBiomeWrapper getPlainsBiomeWrapper()
|
public IBiomeWrapper getPlainsBiomeWrapper()
|
||||||
{
|
{
|
||||||
@@ -168,6 +187,13 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
|||||||
@Override
|
@Override
|
||||||
public IDimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); }
|
public IDimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDimensionName()
|
||||||
|
{
|
||||||
|
return this.level.dimension().location().toString();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EDhApiLevelType getLevelType() { return EDhApiLevelType.CLIENT_LEVEL; }
|
public EDhApiLevelType getLevelType() { return EDhApiLevelType.CLIENT_LEVEL; }
|
||||||
|
|
||||||
@@ -180,7 +206,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
|||||||
public boolean hasSkyLight() { return this.level.dimensionType().hasSkyLight(); }
|
public boolean hasSkyLight() { return this.level.dimensionType().hasSkyLight(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getHeight() { return this.level.getHeight(); }
|
public int getMaxHeight() { return this.level.getHeight(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMinHeight()
|
public int getMinHeight()
|
||||||
@@ -195,12 +221,12 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
|||||||
@Override
|
@Override
|
||||||
public IChunkWrapper tryGetChunk(DhChunkPos pos)
|
public IChunkWrapper tryGetChunk(DhChunkPos pos)
|
||||||
{
|
{
|
||||||
if (!this.level.hasChunk(pos.x, pos.z))
|
if (!this.level.hasChunk(pos.getX(), pos.getZ()))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChunkAccess chunk = this.level.getChunk(pos.x, pos.z, ChunkStatus.EMPTY, false);
|
ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.EMPTY, false);
|
||||||
if (chunk == null)
|
if (chunk == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@@ -229,7 +255,44 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
|||||||
public ClientLevel getWrappedMcObject() { return this.level; }
|
public ClientLevel getWrappedMcObject() { return this.level; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUnload() { LEVEL_WRAPPER_BY_CLIENT_LEVEL.remove(this.level); }
|
public void onUnload()
|
||||||
|
{
|
||||||
|
LEVEL_WRAPPER_BY_CLIENT_LEVEL.remove(this.level);
|
||||||
|
this.parentDhLevel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===================//
|
||||||
|
// generic rendering //
|
||||||
|
//===================//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setParentLevel(IDhLevel parentLevel) { this.parentDhLevel = parentLevel; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IDhApiCustomRenderRegister getRenderRegister()
|
||||||
|
{
|
||||||
|
if (this.parentDhLevel == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.parentDhLevel.getGenericRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Color getCloudColor(float tickDelta)
|
||||||
|
{
|
||||||
|
Vec3 colorVec3 = this.level.getCloudColor(tickDelta);
|
||||||
|
return new Color((float)colorVec3.x, (float)colorVec3.y, (float)colorVec3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
@@ -239,7 +302,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
|||||||
return "Wrapped{null}";
|
return "Wrapped{null}";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Wrapped{" + this.level.toString() + "@" + this.getDimensionType().getDimensionName() + "}";
|
return "Wrapped{" + this.level.toString() + "@" + this.getDimensionName() + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+19
-5
@@ -44,7 +44,9 @@ public class DimensionTypeWrapper implements IDimensionTypeWrapper
|
|||||||
{
|
{
|
||||||
//first we check if the biome has already been wrapped
|
//first we check if the biome has already been wrapped
|
||||||
if (dimensionTypeWrapperMap.containsKey(dimensionType) && dimensionTypeWrapperMap.get(dimensionType) != null)
|
if (dimensionTypeWrapperMap.containsKey(dimensionType) && dimensionTypeWrapperMap.get(dimensionType) != null)
|
||||||
|
{
|
||||||
return dimensionTypeWrapperMap.get(dimensionType);
|
return dimensionTypeWrapperMap.get(dimensionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//if it hasn't been created yet, we create it and save it in the map
|
//if it hasn't been created yet, we create it and save it in the map
|
||||||
@@ -61,22 +63,26 @@ public class DimensionTypeWrapper implements IDimensionTypeWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
private String getDimensionName()
|
||||||
public String getDimensionName()
|
|
||||||
{
|
{
|
||||||
return dimensionType.effectsLocation().getPath();
|
#if MC_VER >= MC_1_17_1
|
||||||
|
return this.dimensionType.effectsLocation().getPath();
|
||||||
|
#else // < 1.17.1
|
||||||
|
// effectsLocation() is marked as client only, so using the backing field directly
|
||||||
|
return dimensionType.effectsLocation.getPath();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasCeiling()
|
public boolean hasCeiling()
|
||||||
{
|
{
|
||||||
return dimensionType.hasCeiling();
|
return this.dimensionType.hasCeiling();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasSkyLight()
|
public boolean hasSkyLight()
|
||||||
{
|
{
|
||||||
return dimensionType.hasSkyLight();
|
return this.dimensionType.hasSkyLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -85,7 +91,15 @@ public class DimensionTypeWrapper implements IDimensionTypeWrapper
|
|||||||
return this.dimensionType;
|
return this.dimensionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getTeleportationScale(IDimensionTypeWrapper to)
|
||||||
|
{
|
||||||
|
return DimensionType.getTeleportationScale(this.dimensionType, (DimensionType) to.getWrappedMcObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
// there's definitely a better way of doing this, but it should work well enough for now
|
||||||
|
@Override
|
||||||
|
public boolean isTheEnd() { return this.getDimensionName().equalsIgnoreCase("the_end"); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj)
|
public boolean equals(Object obj)
|
||||||
|
|||||||
+55
-41
@@ -23,19 +23,18 @@ import java.io.File;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
|
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
|
||||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.cache.ServerBlockDetailMap;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
|
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@@ -49,7 +48,6 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @version 2022-9-16
|
* @version 2022-9-16
|
||||||
@@ -59,8 +57,9 @@ public class ServerLevelWrapper implements IServerLevelWrapper
|
|||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||||
private static final ConcurrentHashMap<ServerLevel, ServerLevelWrapper> LEVEL_WRAPPER_BY_SERVER_LEVEL = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<ServerLevel, ServerLevelWrapper> LEVEL_WRAPPER_BY_SERVER_LEVEL = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
final ServerLevel level;
|
private final ServerLevel level;
|
||||||
ServerBlockDetailMap blockMap = new ServerBlockDetailMap(this);
|
@Deprecated // TODO circular references are bad
|
||||||
|
private IDhLevel parentDhLevel;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -81,29 +80,22 @@ public class ServerLevelWrapper implements IServerLevelWrapper
|
|||||||
// methods //
|
// methods //
|
||||||
//=========//
|
//=========//
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public IClientLevelWrapper tryGetClientLevelWrapper()
|
|
||||||
{
|
|
||||||
MinecraftClientWrapper client = MinecraftClientWrapper.INSTANCE;
|
|
||||||
if (client.mc.level == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ClientLevelWrapper.getWrapper(client.mc.level);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getSaveFolder()
|
public File getSaveFolder()
|
||||||
{
|
{
|
||||||
return level.getChunkSource().getDataStorage().dataFolder;
|
return this.level.getChunkSource().getDataStorage().dataFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DimensionTypeWrapper getDimensionType()
|
public DimensionTypeWrapper getDimensionType()
|
||||||
{
|
{
|
||||||
return DimensionTypeWrapper.getDimensionTypeWrapper(level.dimensionType());
|
return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDimensionName()
|
||||||
|
{
|
||||||
|
return this.level.dimension().location().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -111,25 +103,25 @@ public class ServerLevelWrapper implements IServerLevelWrapper
|
|||||||
|
|
||||||
public ServerLevel getLevel()
|
public ServerLevel getLevel()
|
||||||
{
|
{
|
||||||
return level;
|
return this.level;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasCeiling()
|
public boolean hasCeiling()
|
||||||
{
|
{
|
||||||
return level.dimensionType().hasCeiling();
|
return this.level.dimensionType().hasCeiling();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasSkyLight()
|
public boolean hasSkyLight()
|
||||||
{
|
{
|
||||||
return level.dimensionType().hasSkyLight();
|
return this.level.dimensionType().hasSkyLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getHeight()
|
public int getMaxHeight()
|
||||||
{
|
{
|
||||||
return level.getHeight();
|
return this.level.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -138,51 +130,73 @@ public class ServerLevelWrapper implements IServerLevelWrapper
|
|||||||
#if MC_VER < MC_1_17_1
|
#if MC_VER < MC_1_17_1
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
return level.getMinBuildHeight();
|
return this.level.getMinBuildHeight();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IChunkWrapper tryGetChunk(DhChunkPos pos)
|
public IChunkWrapper tryGetChunk(DhChunkPos pos)
|
||||||
{
|
{
|
||||||
if (!level.hasChunk(pos.x, pos.z)) return null;
|
if (!this.level.hasChunk(pos.getX(), pos.getZ()))
|
||||||
ChunkAccess chunk = level.getChunk(pos.x, pos.z, ChunkStatus.FULL, false);
|
{
|
||||||
if (chunk == null) return null;
|
return null;
|
||||||
return new ChunkWrapper(chunk, level, this);
|
}
|
||||||
|
ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.FULL, false);
|
||||||
|
if (chunk == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ChunkWrapper(chunk, this.level, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasChunkLoaded(int chunkX, int chunkZ)
|
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!
|
// world.hasChunk(chunkX, chunkZ); THIS DOES NOT WORK FOR CLIENT LEVEL CAUSE MOJANG ALWAYS RETURN TRUE FOR THAT!
|
||||||
ChunkSource source = level.getChunkSource();
|
ChunkSource source = this.level.getChunkSource();
|
||||||
return source.hasChunk(chunkX, chunkZ);
|
return source.hasChunk(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBlockStateWrapper getBlockState(DhBlockPos pos)
|
public IBlockStateWrapper getBlockState(DhBlockPos pos)
|
||||||
{
|
{
|
||||||
return BlockStateWrapper.fromBlockState(level.getBlockState(McObjectConverter.Convert(pos)), this);
|
return BlockStateWrapper.fromBlockState(this.level.getBlockState(McObjectConverter.Convert(pos)), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBiomeWrapper getBiome(DhBlockPos pos)
|
public IBiomeWrapper getBiome(DhBlockPos pos)
|
||||||
{
|
{
|
||||||
return BiomeWrapper.getBiomeWrapper(level.getBiome(McObjectConverter.Convert(pos)), this);
|
return BiomeWrapper.getBiomeWrapper(this.level.getBiome(McObjectConverter.Convert(pos)), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServerLevel getWrappedMcObject()
|
public ServerLevel getWrappedMcObject() { return this.level; }
|
||||||
{
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUnload() { LEVEL_WRAPPER_BY_SERVER_LEVEL.remove(this.level); }
|
public void onUnload() { LEVEL_WRAPPER_BY_SERVER_LEVEL.remove(this.level); }
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public void setParentLevel(IDhLevel parentLevel) { this.parentDhLevel = parentLevel; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IDhApiCustomRenderRegister getRenderRegister()
|
||||||
{
|
{
|
||||||
return "Wrapped{" + level.toString() + "@" + getDimensionType().getDimensionName() + "}";
|
if (this.parentDhLevel == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.parentDhLevel.getGenericRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() { return "Wrapped{" + this.level.toString() + "@" + this.getDimensionName() + "}"; }
|
||||||
|
|
||||||
}
|
}
|
||||||
+307
-181
@@ -35,6 +35,7 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
|||||||
import com.seibel.distanthorizons.core.util.objects.EventTimer;
|
import com.seibel.distanthorizons.core.util.objects.EventTimer;
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
@@ -109,8 +110,6 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"),
|
new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"),
|
||||||
() -> Config.Client.Advanced.Logging.logWorldGenLoadEvent.get());
|
() -> Config.Client.Advanced.Logging.logWorldGenLoadEvent.get());
|
||||||
|
|
||||||
//TODO: Make actual proper support for StarLight
|
|
||||||
|
|
||||||
public static class PerfCalculator
|
public static class PerfCalculator
|
||||||
{
|
{
|
||||||
private static final String[] TIME_NAMES = {
|
private static final String[] TIME_NAMES = {
|
||||||
@@ -225,8 +224,8 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
// constructors //
|
// constructors //
|
||||||
//==============//
|
//==============//
|
||||||
|
|
||||||
public static ImmutableMap<EDhApiWorldGenerationStep, Integer> BorderNeeded;
|
public static final ImmutableMap<EDhApiWorldGenerationStep, Integer> WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP;
|
||||||
public static int MaxBorderNeeded;
|
public static final int MAX_WORLD_GEN_CHUNK_BORDER_NEEDED;
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
@@ -254,8 +253,13 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
builder.put(EDhApiWorldGenerationStep.LIQUID_CARVERS, 0);
|
builder.put(EDhApiWorldGenerationStep.LIQUID_CARVERS, 0);
|
||||||
builder.put(EDhApiWorldGenerationStep.FEATURES, 0);
|
builder.put(EDhApiWorldGenerationStep.FEATURES, 0);
|
||||||
builder.put(EDhApiWorldGenerationStep.LIGHT, 0);
|
builder.put(EDhApiWorldGenerationStep.LIGHT, 0);
|
||||||
BorderNeeded = builder.build();
|
WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP = builder.build();
|
||||||
MaxBorderNeeded = BorderNeeded.values().stream().mapToInt(Integer::intValue).max().getAsInt();
|
|
||||||
|
// TODO this is a test to see if the additional boarder is actually necessary or not.
|
||||||
|
// If world generators end up having infinite loops or other unexplained issues,
|
||||||
|
// this should be set back to the commented out logic below
|
||||||
|
MAX_WORLD_GEN_CHUNK_BORDER_NEEDED = 0;
|
||||||
|
//MAX_WORLD_GEN_CHUNK_BORDER_NEEDED = WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP.values().stream().mapToInt(Integer::intValue).max().getAsInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BatchGenerationEnvironment(IDhServerLevel serverlevel)
|
public BatchGenerationEnvironment(IDhServerLevel serverlevel)
|
||||||
@@ -294,6 +298,9 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=================//
|
||||||
|
// synchronization //
|
||||||
|
//=================//
|
||||||
|
|
||||||
public <T> T joinSync(CompletableFuture<T> future)
|
public <T> T joinSync(CompletableFuture<T> future)
|
||||||
{
|
{
|
||||||
@@ -344,8 +351,11 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
}
|
}
|
||||||
else if (event.hasTimeout(Config.Client.Advanced.WorldGenerator.worldGenerationTimeoutLengthInSeconds.get(), TimeUnit.SECONDS))
|
else if (event.hasTimeout(Config.Client.Advanced.WorldGenerator.worldGenerationTimeoutLengthInSeconds.get(), TimeUnit.SECONDS))
|
||||||
{
|
{
|
||||||
EVENT_LOGGER.error("Batching World Generator: " + event + " timed out and terminated!");
|
EVENT_LOGGER.warn(
|
||||||
EVENT_LOGGER.info("Dump PrefEvent: " + event.timer);
|
"Batching World Generator: [" + event + "] timed out and terminated after ["+Config.Client.Advanced.WorldGenerator.worldGenerationTimeoutLengthInSeconds.get()+"] seconds. " +
|
||||||
|
"\nYour computer might be overloaded or your world gen mods might be causing world gen to take longer than expected. " +
|
||||||
|
"\nEither increase DH's world gen timeout or reduce your computer's CPU load.");
|
||||||
|
EVENT_LOGGER.debug("Dump PrefEvent: " + event.timer);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!event.terminate())
|
if (!event.terminate())
|
||||||
@@ -368,31 +378,251 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProtoChunk EmptyChunk(ServerLevel level, ChunkPos chunkPos)
|
|
||||||
|
|
||||||
|
//==================//
|
||||||
|
// world generation //
|
||||||
|
//==================//
|
||||||
|
|
||||||
|
public void generateLodFromList(GenerationEvent genEvent) throws InterruptedException
|
||||||
{
|
{
|
||||||
return new ProtoChunk(chunkPos, UpgradeData.EMPTY
|
EVENT_LOGGER.debug("Lod Generate Event: " + genEvent.minPos);
|
||||||
#if MC_VER >= MC_1_17_1 , level #endif
|
|
||||||
#if MC_VER >= MC_1_18_2 , level.registryAccess().registryOrThrow(
|
|
||||||
#if MC_VER < MC_1_19_4
|
|
||||||
Registry.BIOME_REGISTRY
|
|
||||||
#else
|
|
||||||
Registries.BIOME
|
|
||||||
#endif
|
|
||||||
), null #endif
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// Minecraft's generation events expect odd chunk width areas (3x3, 7x7, or 11x11),
|
||||||
|
// but DH submits square generation events (4x4).
|
||||||
|
// We handle this later, although that handling would need to change if the gen size ever changed.
|
||||||
|
LodUtil.assertTrue(genEvent.size % 2 == 0, "Generation events are expected to be an evan number of chunks wide.");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int borderSize = MAX_WORLD_GEN_CHUNK_BORDER_NEEDED;
|
||||||
|
// genEvent.size - 1 converts the even width size to an odd number for MC compatability
|
||||||
|
int refSize = (genEvent.size - 1) + (borderSize * 2);
|
||||||
|
int refPosX = genEvent.minPos.getX() - borderSize;
|
||||||
|
int refPosZ = genEvent.minPos.getZ() - borderSize;
|
||||||
|
|
||||||
|
LightGetterAdaptor lightGetterAdaptor = new LightGetterAdaptor(this.params.level);
|
||||||
|
DummyLightEngine dummyLightEngine = new DummyLightEngine(lightGetterAdaptor);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//====================================//
|
||||||
|
// offset and generate odd width area //
|
||||||
|
//====================================//
|
||||||
|
|
||||||
|
// reused data between each offset
|
||||||
|
HashMap<DhChunkPos, ChunkLightStorage> chunkSkyLightingByDhPos = new HashMap<>();
|
||||||
|
HashMap<DhChunkPos, ChunkLightStorage> chunkBlockLightingByDhPos = new HashMap<>();
|
||||||
|
HashMap<DhChunkPos, ChunkAccess> generatedChunkByDhPos = new HashMap<>();
|
||||||
|
HashMap<DhChunkPos, ChunkWrapper> chunkWrappersByDhPos = new HashMap<>();
|
||||||
|
|
||||||
|
// offset 1 chunk in both X and Z direction so we can generate an even number of chunks wide
|
||||||
|
// while still submitting odd numbers to MC's internal generators
|
||||||
|
for (int xOffset = 0; xOffset < 2; xOffset++)
|
||||||
|
{
|
||||||
|
// final is so the offset can be used in lambdas
|
||||||
|
final int xOffsetFinal = xOffset;
|
||||||
|
for (int zOffset = 0; zOffset < 2; zOffset++)
|
||||||
|
{
|
||||||
|
final int zOffsetFinal = zOffset;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// variable setup //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
int radius = refSize / 2;
|
||||||
|
int centerX = refPosX + radius + xOffset;
|
||||||
|
int centerZ = refPosZ + radius + zOffset;
|
||||||
|
|
||||||
|
// get/create the list of chunks we're going to generate
|
||||||
|
ArrayGridList<ChunkAccess> regionChunks = new ArrayGridList<>(
|
||||||
|
refSize,
|
||||||
|
(x, z) -> this.generateEmptyChunk(
|
||||||
|
x + refPosX + xOffsetFinal,
|
||||||
|
z + refPosZ + zOffsetFinal,
|
||||||
|
chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, generatedChunkByDhPos));
|
||||||
|
ChunkAccess centerChunk = regionChunks.stream().filter(chunk -> chunk.getPos().x == centerX && chunk.getPos().z == centerZ).findFirst().get();
|
||||||
|
|
||||||
|
genEvent.refreshTimeout();
|
||||||
|
DhLitWorldGenRegion region = new DhLitWorldGenRegion(
|
||||||
|
centerX, centerZ,
|
||||||
|
centerChunk,
|
||||||
|
this.params.level, dummyLightEngine, regionChunks,
|
||||||
|
ChunkStatus.STRUCTURE_STARTS, radius,
|
||||||
|
// this method shouldn't be necessary since we're passing in a pre-populated
|
||||||
|
// list of chunks, but just in case
|
||||||
|
(x, z) -> this.generateEmptyChunk(x, z, chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, generatedChunkByDhPos)
|
||||||
|
);
|
||||||
|
lightGetterAdaptor.setRegion(region);
|
||||||
|
genEvent.threadedParam.makeStructFeat(region, this.params);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========================//
|
||||||
|
// create chunk wrappers //
|
||||||
|
// and get existing chunks //
|
||||||
|
//=========================//
|
||||||
|
|
||||||
|
ArrayGridList<ChunkWrapper> chunkWrapperList = new ArrayGridList<>(regionChunks.gridSize);
|
||||||
|
regionChunks.forEachPos((relX, relZ) ->
|
||||||
|
{
|
||||||
|
// ArrayGridList's use relative positions and don't have a center position
|
||||||
|
// so we need to use the offsetFinal to select the correct position
|
||||||
|
DhChunkPos chunkPos = new DhChunkPos(relX + xOffsetFinal, relZ + zOffsetFinal);
|
||||||
|
ChunkAccess chunk = regionChunks.get(relX, relZ);
|
||||||
|
|
||||||
|
if (chunkWrappersByDhPos.containsKey(chunkPos))
|
||||||
|
{
|
||||||
|
chunkWrapperList.set(relX, relZ, chunkWrappersByDhPos.get(chunkPos));
|
||||||
|
}
|
||||||
|
else if (chunk != null)
|
||||||
|
{
|
||||||
|
// wrap the chunk
|
||||||
|
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, region, this.serverlevel.getLevelWrapper());
|
||||||
|
chunkWrapperList.set(relX, relZ, chunkWrapper);
|
||||||
|
|
||||||
|
// try setting the wrapper's lighting
|
||||||
|
if (chunkBlockLightingByDhPos.containsKey(chunkWrapper.getChunkPos()))
|
||||||
|
{
|
||||||
|
chunkWrapper.setBlockLightStorage(chunkBlockLightingByDhPos.get(chunkWrapper.getChunkPos()));
|
||||||
|
chunkWrapper.setSkyLightStorage(chunkSkyLightingByDhPos.get(chunkWrapper.getChunkPos()));
|
||||||
|
chunkWrapper.setUseDhLighting(true);
|
||||||
|
chunkWrapper.setIsDhLightCorrect(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
chunkWrappersByDhPos.put(chunkPos, chunkWrapper);
|
||||||
|
}
|
||||||
|
else //if (chunk == null)
|
||||||
|
{
|
||||||
|
LodUtil.assertNotReach("Programmer Error: No chunk found in grid list, position offset is likely wrong.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=================//
|
||||||
|
// generate chunks //
|
||||||
|
//=================//
|
||||||
|
|
||||||
|
this.generateDirect(genEvent, chunkWrapperList, borderSize, genEvent.targetGenerationStep, region);
|
||||||
|
|
||||||
|
genEvent.timer.nextEvent("cleanup");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========================//
|
||||||
|
// submit generated chunks //
|
||||||
|
//=========================//
|
||||||
|
|
||||||
|
for (DhChunkPos dhChunkPos : chunkWrappersByDhPos.keySet())
|
||||||
|
{
|
||||||
|
ChunkWrapper wrappedChunk = chunkWrappersByDhPos.get(dhChunkPos);
|
||||||
|
ChunkAccess target = wrappedChunk.getChunk();
|
||||||
|
if (target instanceof LevelChunk)
|
||||||
|
{
|
||||||
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
|
((LevelChunk) target).setLoaded(true);
|
||||||
|
#else
|
||||||
|
((LevelChunk) target).loaded = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wrappedChunk.isLightCorrect())
|
||||||
|
{
|
||||||
|
throw new RuntimeException("The generated chunk somehow has isLightCorrect() returning false");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isFull = ChunkWrapper.getStatus(target) == ChunkStatus.FULL || target instanceof LevelChunk;
|
||||||
|
#if MC_VER >= MC_1_18_2
|
||||||
|
boolean isPartial = target.isOldNoiseGeneration();
|
||||||
|
#endif
|
||||||
|
if (isFull)
|
||||||
|
{
|
||||||
|
LOAD_LOGGER.debug("Detected full existing chunk at {}", target.getPos());
|
||||||
|
genEvent.resultConsumer.accept(wrappedChunk);
|
||||||
|
}
|
||||||
|
#if MC_VER >= MC_1_18_2
|
||||||
|
else if (isPartial)
|
||||||
|
{
|
||||||
|
LOAD_LOGGER.debug("Detected old existing chunk at {}", target.getPos());
|
||||||
|
genEvent.resultConsumer.accept(wrappedChunk);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (ChunkWrapper.getStatus(target) == ChunkStatus.EMPTY)
|
||||||
|
{
|
||||||
|
genEvent.resultConsumer.accept(wrappedChunk);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
genEvent.resultConsumer.accept(wrappedChunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
genEvent.timer.complete();
|
||||||
|
genEvent.refreshTimeout();
|
||||||
|
if (PREF_LOGGER.canMaybeLog())
|
||||||
|
{
|
||||||
|
genEvent.threadedParam.perf.recordEvent(genEvent.timer);
|
||||||
|
PREF_LOGGER.debugInc("{}", genEvent.timer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
private ChunkAccess generateEmptyChunk(
|
||||||
|
int x, int z,
|
||||||
|
HashMap<DhChunkPos, ChunkLightStorage> chunkSkyLightingByDhPos,
|
||||||
|
HashMap<DhChunkPos, ChunkLightStorage> chunkBlockLightingByDhPos,
|
||||||
|
HashMap<DhChunkPos, ChunkAccess> generatedChunkByDhPos)
|
||||||
|
{
|
||||||
|
ChunkPos chunkPos = new ChunkPos(x, z);
|
||||||
|
DhChunkPos dhChunkPos = new DhChunkPos(x, z);
|
||||||
|
|
||||||
public ChunkAccess loadOrMakeChunk(ChunkPos chunkPos)
|
if (generatedChunkByDhPos.containsKey(dhChunkPos))
|
||||||
|
{
|
||||||
|
return generatedChunkByDhPos.get(dhChunkPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ChunkAccess newChunk = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// get the chunk
|
||||||
|
CompoundTag chunkData = this.getChunkNbtData(chunkPos);
|
||||||
|
newChunk = this.loadOrMakeChunk(chunkPos, chunkData);
|
||||||
|
|
||||||
|
if (Config.Client.Advanced.LodBuilding.pullLightingForPregeneratedChunks.get())
|
||||||
|
{
|
||||||
|
// attempt to get chunk lighting
|
||||||
|
ChunkLoader.CombinedChunkLightStorage combinedLights = ChunkLoader.readLight(newChunk, chunkData);
|
||||||
|
if (combinedLights != null)
|
||||||
|
{
|
||||||
|
chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage);
|
||||||
|
chunkBlockLightingByDhPos.put(dhChunkPos, combinedLights.blockLightStorage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (RuntimeException loadChunkError)
|
||||||
|
{
|
||||||
|
// Continue...
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newChunk == null)
|
||||||
|
{
|
||||||
|
newChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY
|
||||||
|
#if MC_VER >= MC_1_17_1 , this.params.level #endif
|
||||||
|
#if MC_VER >= MC_1_18_2 , this.params.biomes, null #endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
generatedChunkByDhPos.put(dhChunkPos, newChunk);
|
||||||
|
return newChunk;
|
||||||
|
}
|
||||||
|
private CompoundTag getChunkNbtData(ChunkPos chunkPos)
|
||||||
{
|
{
|
||||||
ServerLevel level = this.params.level;
|
ServerLevel level = this.params.level;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//====================//
|
|
||||||
// get the chunk data //
|
|
||||||
//====================//
|
|
||||||
|
|
||||||
CompoundTag chunkData = null;
|
CompoundTag chunkData = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -425,175 +655,52 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
LOAD_LOGGER.error("DistantHorizons: Couldn't load or make chunk " + chunkPos + ". Error: " + e.getMessage(), e);
|
LOAD_LOGGER.error("DistantHorizons: Couldn't load or make chunk " + chunkPos + ". Error: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return chunkData;
|
||||||
|
}
|
||||||
//========================//
|
private ChunkAccess loadOrMakeChunk(ChunkPos chunkPos, CompoundTag chunkData)
|
||||||
// convert the chunk data //
|
{
|
||||||
//========================//
|
ServerLevel level = this.params.level;
|
||||||
|
|
||||||
if (chunkData == null)
|
if (chunkData == null)
|
||||||
{
|
{
|
||||||
return EmptyChunk(level, chunkPos);
|
return CreateEmptyChunk(level, chunkPos);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LOAD_LOGGER.info("DistantHorizons: Loading chunk [" + chunkPos + "] from disk.");
|
LOAD_LOGGER.debug("DistantHorizons: Loading chunk [" + chunkPos + "] from disk.");
|
||||||
return ChunkLoader.read(level, chunkPos, chunkData);
|
return ChunkLoader.read(level, chunkPos, chunkData);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
LOAD_LOGGER.error(
|
LOAD_LOGGER.error(
|
||||||
"DistantHorizons: couldn't load or make chunk at ["+chunkPos+"]." +
|
"DistantHorizons: couldn't load or make chunk at ["+chunkPos+"]." +
|
||||||
"Please try optimizing your world to fix this issue. \n" +
|
"Please try optimizing your world to fix this issue. \n" +
|
||||||
"World optimization can be done from the singleplayer world selection screen.\n" +
|
"World optimization can be done from the singleplayer world selection screen.\n" +
|
||||||
"Error: ["+e.getMessage()+"]."
|
"Error: ["+e.getMessage()+"]."
|
||||||
, e);
|
, e);
|
||||||
|
|
||||||
return EmptyChunk(level, chunkPos);
|
return CreateEmptyChunk(level, chunkPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static ProtoChunk CreateEmptyChunk(ServerLevel level, ChunkPos chunkPos)
|
||||||
private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, int border)
|
|
||||||
{
|
{
|
||||||
return new ArrayGridList<>(total, border, total.gridSize - border);
|
return new ProtoChunk(chunkPos, UpgradeData.EMPTY
|
||||||
|
#if MC_VER >= MC_1_17_1 , level #endif
|
||||||
|
#if MC_VER >= MC_1_18_2 , level.registryAccess().registryOrThrow(
|
||||||
|
#if MC_VER < MC_1_19_4
|
||||||
|
Registry.BIOME_REGISTRY
|
||||||
|
#else
|
||||||
|
Registries.BIOME
|
||||||
|
#endif
|
||||||
|
), null #endif
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, EDhApiWorldGenerationStep step)
|
|
||||||
{
|
|
||||||
return GetCutoutFrom(total, MaxBorderNeeded - BorderNeeded.get(step));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void generateLodFromList(GenerationEvent genEvent) throws InterruptedException
|
|
||||||
{
|
|
||||||
EVENT_LOGGER.debug("Lod Generate Event: " + genEvent.minPos);
|
|
||||||
|
|
||||||
ArrayGridList<ChunkWrapper> chunkWrapperList;
|
|
||||||
DhLitWorldGenRegion region;
|
|
||||||
DummyLightEngine lightEngine;
|
|
||||||
LightGetterAdaptor adaptor;
|
|
||||||
|
|
||||||
int borderSize = MaxBorderNeeded;
|
|
||||||
int refSize = genEvent.size + borderSize * 2;
|
|
||||||
int refPosX = genEvent.minPos.x - borderSize;
|
|
||||||
int refPosZ = genEvent.minPos.z - borderSize;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ArrayGridList<ChunkAccess> totalChunks;
|
|
||||||
|
|
||||||
adaptor = new LightGetterAdaptor(this.params.level);
|
|
||||||
lightEngine = new DummyLightEngine(adaptor);
|
|
||||||
|
|
||||||
EmptyChunkGenerator generator = (int x, int z) ->
|
|
||||||
{
|
|
||||||
ChunkPos chunkPos = new ChunkPos(x, z);
|
|
||||||
ChunkAccess target = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
target = this.loadOrMakeChunk(chunkPos);
|
|
||||||
}
|
|
||||||
catch (RuntimeException e2)
|
|
||||||
{
|
|
||||||
// Continue...
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target == null)
|
|
||||||
{
|
|
||||||
target = new ProtoChunk(chunkPos, UpgradeData.EMPTY
|
|
||||||
#if MC_VER >= MC_1_17_1 , params.level #endif
|
|
||||||
#if MC_VER >= MC_1_18_2 , params.biomes, null #endif
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return target;
|
|
||||||
};
|
|
||||||
|
|
||||||
totalChunks = new ArrayGridList<>(refSize, (x, z) -> generator.generate(x + refPosX, z + refPosZ));
|
|
||||||
|
|
||||||
genEvent.refreshTimeout();
|
|
||||||
region = new DhLitWorldGenRegion(params.level, lightEngine, totalChunks,
|
|
||||||
ChunkStatus.STRUCTURE_STARTS, refSize / 2, generator);
|
|
||||||
adaptor.setRegion(region);
|
|
||||||
genEvent.threadedParam.makeStructFeat(region, params);
|
|
||||||
|
|
||||||
|
|
||||||
chunkWrapperList = new ArrayGridList<>(totalChunks.gridSize);
|
|
||||||
totalChunks.forEachPos((x, z) ->
|
|
||||||
{
|
|
||||||
ChunkAccess chunk = totalChunks.get(x, z);
|
|
||||||
if (chunk != null)
|
|
||||||
{
|
|
||||||
chunkWrapperList.set(x, z, new ChunkWrapper(chunk, region, serverlevel.getLevelWrapper()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.generateDirect(genEvent, chunkWrapperList, borderSize, genEvent.targetGenerationStep, region);
|
|
||||||
genEvent.timer.nextEvent("cleanup");
|
|
||||||
}
|
|
||||||
catch (StepStructureStart.StructStartCorruptedException f)
|
|
||||||
{
|
|
||||||
genEvent.threadedParam.markAsInvalid();
|
|
||||||
throw (RuntimeException) f.getCause();
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayGridList<ChunkWrapper> finalGenChunks = GetCutoutFrom(chunkWrapperList, borderSize);
|
|
||||||
for (int offsetY = 0; offsetY < finalGenChunks.gridSize; offsetY++)
|
|
||||||
{
|
|
||||||
for (int offsetX = 0; offsetX < finalGenChunks.gridSize; offsetX++)
|
|
||||||
{
|
|
||||||
ChunkWrapper wrappedChunk = finalGenChunks.get(offsetX, offsetY);
|
|
||||||
ChunkAccess target = wrappedChunk.getChunk();
|
|
||||||
if (target instanceof LevelChunk)
|
|
||||||
{
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
|
||||||
((LevelChunk) target).setLoaded(true);
|
|
||||||
#else
|
|
||||||
((LevelChunk) target).loaded = true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!wrappedChunk.isLightCorrect())
|
|
||||||
{
|
|
||||||
throw new RuntimeException("The generated chunk somehow has isLightCorrect() returning false");
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isFull = target.getStatus() == ChunkStatus.FULL || target instanceof LevelChunk;
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
boolean isPartial = target.isOldNoiseGeneration();
|
|
||||||
#endif
|
|
||||||
if (isFull)
|
|
||||||
{
|
|
||||||
LOAD_LOGGER.info("Detected full existing chunk at {}", target.getPos());
|
|
||||||
genEvent.resultConsumer.accept(wrappedChunk);
|
|
||||||
}
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
else if (isPartial)
|
|
||||||
{
|
|
||||||
LOAD_LOGGER.info("Detected old existing chunk at {}", target.getPos());
|
|
||||||
genEvent.resultConsumer.accept(wrappedChunk);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else if (target.getStatus() == ChunkStatus.EMPTY)
|
|
||||||
{
|
|
||||||
genEvent.resultConsumer.accept(wrappedChunk);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
genEvent.resultConsumer.accept(wrappedChunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
genEvent.timer.complete();
|
|
||||||
genEvent.refreshTimeout();
|
|
||||||
if (PREF_LOGGER.canMaybeLog())
|
|
||||||
{
|
|
||||||
genEvent.threadedParam.perf.recordEvent(genEvent.timer);
|
|
||||||
PREF_LOGGER.infoInc("{}", genEvent.timer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void generateDirect(
|
public void generateDirect(
|
||||||
GenerationEvent genEvent, ArrayGridList<ChunkWrapper> chunksToGenerate, int border,
|
GenerationEvent genEvent, ArrayGridList<ChunkWrapper> chunksToGenerate, int border,
|
||||||
@@ -694,7 +801,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
for (int i = 0; i < chunksToGenerate.size(); i++) // regular for loop since enhanced for loops increase GC pressure slightly
|
for (int i = 0; i < chunksToGenerate.size(); i++) // regular for loop since enhanced for loops increase GC pressure slightly
|
||||||
{
|
{
|
||||||
ChunkWrapper chunkWrapper = chunksToGenerate.get(i);
|
ChunkWrapper chunkWrapper = chunksToGenerate.get(i);
|
||||||
if (chunkWrapper.getChunk().getStatus() != ChunkStatus.EMPTY)
|
if (chunkWrapper.getStatus() != ChunkStatus.EMPTY)
|
||||||
{
|
{
|
||||||
iChunkWrapperList.add(chunkWrapper);
|
iChunkWrapperList.add(chunkWrapper);
|
||||||
}
|
}
|
||||||
@@ -715,19 +822,20 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
// if this isn't done everything else afterward may fail
|
// if this isn't done everything else afterward may fail
|
||||||
Heightmap.primeHeightmaps(((ChunkWrapper)centerChunk).getChunk(), ChunkStatus.FEATURES.heightmapsAfter());
|
Heightmap.primeHeightmaps(((ChunkWrapper)centerChunk).getChunk(), ChunkStatus.FEATURES.heightmapsAfter());
|
||||||
|
|
||||||
// populate the lighting
|
// pre-generated chunks should have lighting but new ones won't
|
||||||
DhLightingEngine.INSTANCE.lightChunk(centerChunk, iChunkWrapperList, maxSkyLight);
|
if (!centerChunk.isLightCorrect())
|
||||||
|
{
|
||||||
|
DhLightingEngine.INSTANCE.lightChunk(centerChunk, iChunkWrapperList, maxSkyLight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
genEvent.refreshTimeout();
|
genEvent.refreshTimeout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, int border) { return new ArrayGridList<>(total, border, total.gridSize - border); }
|
||||||
|
//private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, EDhApiWorldGenerationStep step) { return GetCutoutFrom(total, MaxBorderNeeded - WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP.get(step)); }
|
||||||
|
private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, EDhApiWorldGenerationStep step) { return GetCutoutFrom(total, 0); }
|
||||||
|
|
||||||
public interface EmptyChunkGenerator
|
|
||||||
{
|
|
||||||
ChunkAccess generate(int x, int z);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getEventCount() { return this.generationEventList.size(); }
|
public int getEventCount() { return this.generationEventList.size(); }
|
||||||
@@ -776,6 +884,12 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
return genEvent.future;
|
return genEvent.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper methods //
|
||||||
|
//================//
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called before code that may run for an extended period of time. <br>
|
* Called before code that may run for an extended period of time. <br>
|
||||||
* This is necessary to allow canceling world gen since waiting
|
* This is necessary to allow canceling world gen since waiting
|
||||||
@@ -789,4 +903,16 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper classes //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface IEmptyChunkGeneratorFunc
|
||||||
|
{
|
||||||
|
ChunkAccess generate(int x, int z);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+6
-22
@@ -43,6 +43,7 @@ public final class GenerationEvent
|
|||||||
public final int id;
|
public final int id;
|
||||||
public final ThreadedParameters threadedParam;
|
public final ThreadedParameters threadedParam;
|
||||||
public final DhChunkPos minPos;
|
public final DhChunkPos minPos;
|
||||||
|
/** the number of chunks wide this event is */
|
||||||
public final int size;
|
public final int size;
|
||||||
public final EDhApiWorldGenerationStep targetGenerationStep;
|
public final EDhApiWorldGenerationStep targetGenerationStep;
|
||||||
public EventTimer timer = null;
|
public EventTimer timer = null;
|
||||||
@@ -73,10 +74,10 @@ public final class GenerationEvent
|
|||||||
EDhApiWorldGenerationStep target, Consumer<IChunkWrapper> resultConsumer,
|
EDhApiWorldGenerationStep target, Consumer<IChunkWrapper> resultConsumer,
|
||||||
ExecutorService worldGeneratorThreadPool)
|
ExecutorService worldGeneratorThreadPool)
|
||||||
{
|
{
|
||||||
if (size % 2 == 0)
|
//if (size % 2 == 0)
|
||||||
{
|
//{
|
||||||
size += 1; // size must be odd for vanilla world gen regions to work
|
// size += 1; // size must be odd for vanilla world gen regions to work
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
|
||||||
GenerationEvent generationEvent = new GenerationEvent(minPos, size, genEnvironment, target, resultConsumer);
|
GenerationEvent generationEvent = new GenerationEvent(minPos, size, genEnvironment, target, resultConsumer);
|
||||||
@@ -93,9 +94,7 @@ public final class GenerationEvent
|
|||||||
//LOGGER.info("generating [{}]", event.minPos);
|
//LOGGER.info("generating [{}]", event.minPos);
|
||||||
genEnvironment.generateLodFromList(generationEvent);
|
genEnvironment.generateLodFromList(generationEvent);
|
||||||
}
|
}
|
||||||
catch (InterruptedException ignored)
|
catch (InterruptedException ignored) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
BatchGenerationEnvironment.isDistantGeneratorThread.remove();
|
BatchGenerationEnvironment.isDistantGeneratorThread.remove();
|
||||||
@@ -126,21 +125,6 @@ public final class GenerationEvent
|
|||||||
return this.future.isCancelled();
|
return this.future.isCancelled();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean tooClose(int minX, int minZ, int width)
|
|
||||||
{
|
|
||||||
int aMinX = this.minPos.x;
|
|
||||||
int aMinZ = this.minPos.z;
|
|
||||||
int aSize = this.size;
|
|
||||||
// Account for required empty chunks in the border
|
|
||||||
aSize += 1;
|
|
||||||
width += 1;
|
|
||||||
// Do a AABB to AABB intersection test
|
|
||||||
return (aMinX + aSize >= minX &&
|
|
||||||
aMinX <= minX + width &&
|
|
||||||
aMinZ + aSize >= minZ &&
|
|
||||||
aMinZ <= minZ + width);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refreshTimeout()
|
public void refreshTimeout()
|
||||||
{
|
{
|
||||||
this.timeoutTime = System.nanoTime();
|
this.timeoutTime = System.nanoTime();
|
||||||
|
|||||||
+300
-133
@@ -22,9 +22,14 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.Dynamic;
|
import com.mojang.serialization.Dynamic;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
|
|
||||||
@@ -44,6 +49,7 @@ import net.minecraft.core.registries.Registries;
|
|||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.ListTag;
|
import net.minecraft.nbt.ListTag;
|
||||||
import net.minecraft.nbt.NbtOps;
|
import net.minecraft.nbt.NbtOps;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.level.*;
|
import net.minecraft.world.level.*;
|
||||||
@@ -79,6 +85,9 @@ import net.minecraft.world.level.material.Fluids;
|
|||||||
#if MC_VER == MC_1_20_6
|
#if MC_VER == MC_1_20_6
|
||||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.chunk.status.ChunkType;
|
import net.minecraft.world.level.chunk.status.ChunkType;
|
||||||
|
#elif MC_VER >= MC_1_21_1
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkType;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
import net.minecraft.world.level.material.Fluid;
|
import net.minecraft.world.level.material.Fluid;
|
||||||
@@ -100,138 +109,13 @@ public class ChunkLoader
|
|||||||
private static final String FLUID_TICKS_TAG_PRE18 = "LiquidTicks";
|
private static final String FLUID_TICKS_TAG_PRE18 = "LiquidTicks";
|
||||||
private static final ConfigBasedLogger LOGGER = BatchGenerationEnvironment.LOAD_LOGGER;
|
private static final ConfigBasedLogger LOGGER = BatchGenerationEnvironment.LOAD_LOGGER;
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
private static boolean lightingSectionErrorLogged = false;
|
||||||
private static BlendingData readBlendingData(CompoundTag chunkData)
|
|
||||||
{
|
|
||||||
BlendingData blendingData = null;
|
|
||||||
if (chunkData.contains("blending_data", 10))
|
|
||||||
{
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
Dynamic<CompoundTag> blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data"));
|
|
||||||
blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial(LOGGER::error).orElse(null);
|
|
||||||
}
|
|
||||||
return blendingData;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData)
|
|
||||||
{
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
#if MC_VER < MC_1_19_4
|
|
||||||
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
|
|
||||||
#else
|
|
||||||
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registries.BIOME);
|
|
||||||
#endif
|
|
||||||
#if MC_VER < MC_1_18_2
|
|
||||||
Codec<PalettedContainer<Biome>> biomeCodec = PalettedContainer.codec(
|
|
||||||
biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
|
|
||||||
#elif MC_VER < MC_1_19_2
|
|
||||||
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
|
|
||||||
#endif
|
|
||||||
int i = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif
|
|
||||||
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);
|
|
||||||
|
|
||||||
for (int j = 0; j < tagSections.size(); ++j)
|
//============//
|
||||||
{
|
// read chunk //
|
||||||
CompoundTag tagSection = tagSections.getCompound(j);
|
//============//
|
||||||
int sectionYPos = tagSection.getByte("Y");
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_18_2
|
|
||||||
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 MC_VER < MC_1_17_1 sectionYPos #else level.getSectionIndexFromSectionY(sectionYPos) #endif ]
|
|
||||||
= levelChunkSection;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
int sectionId = level.getSectionIndexFromSectionY(sectionYPos);
|
|
||||||
if (sectionId >= 0 && sectionId < chunkSections.length)
|
|
||||||
{
|
|
||||||
PalettedContainer<BlockState> blockStateContainer;
|
|
||||||
#if MC_VER < MC_1_18_2
|
|
||||||
PalettedContainer<Biome> biomeContainer;
|
|
||||||
#else
|
|
||||||
PalettedContainer<Holder<Biome>> biomeContainer;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
blockStateContainer = tagSection.contains("block_states", 10)
|
|
||||||
? BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagSection.getCompound("block_states")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string))
|
|
||||||
#if MC_VER < MC_1_20_6 .getOrThrow(false, LOGGER::error) #else .getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null)) #endif
|
|
||||||
: new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_18_2
|
|
||||||
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
|
|
||||||
|
|
||||||
biomeContainer = tagSection.contains("biomes", 10)
|
|
||||||
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, i, (String) string))
|
|
||||||
#if MC_VER < MC_1_20_6 .getOrThrow(false, LOGGER::error) #else .getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null)) #endif
|
|
||||||
: new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(), biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_20_1
|
|
||||||
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
|
|
||||||
#else
|
|
||||||
chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
return chunkSections;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
|
|
||||||
{
|
|
||||||
CompoundTag tagHeightmaps = chunkData.getCompound("Heightmaps");
|
|
||||||
for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
|
|
||||||
{
|
|
||||||
String heightmap = type.getSerializationKey();
|
|
||||||
if (tagHeightmaps.contains(heightmap, 12))
|
|
||||||
chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap));
|
|
||||||
}
|
|
||||||
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
|
|
||||||
{
|
|
||||||
ListTag tagPostProcessings = chunkData.getList("PostProcessing", 9);
|
|
||||||
for (int n = 0; n < tagPostProcessings.size(); ++n)
|
|
||||||
{
|
|
||||||
ListTag listTag3 = tagPostProcessings.getList(n);
|
|
||||||
for (int o = 0; o < listTag3.size(); ++o)
|
|
||||||
{
|
|
||||||
chunk.addPackedPostProcess(listTag3.getShort(o), n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType #else ChunkType #endif readChunkType(CompoundTag tagLevel)
|
|
||||||
{
|
|
||||||
ChunkStatus chunkStatus = ChunkStatus.byName(tagLevel.getString("Status"));
|
|
||||||
if (chunkStatus != null)
|
|
||||||
{
|
|
||||||
return chunkStatus.getChunkType();
|
|
||||||
}
|
|
||||||
|
|
||||||
return #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType.PROTOCHUNK; #else ChunkType.PROTOCHUNK; #endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LevelChunk read(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData)
|
public static LevelChunk read(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData)
|
||||||
{
|
{
|
||||||
@@ -244,7 +128,7 @@ public class ChunkLoader
|
|||||||
ChunkPos actualPos = new ChunkPos(tagLevel.getInt("xPos"), tagLevel.getInt("zPos"));
|
ChunkPos actualPos = new ChunkPos(tagLevel.getInt("xPos"), tagLevel.getInt("zPos"));
|
||||||
if (!Objects.equals(chunkPos, actualPos))
|
if (!Objects.equals(chunkPos, actualPos))
|
||||||
{
|
{
|
||||||
#if MC_VER > MC_1_17_1
|
#if MC_VER >= MC_1_18_2
|
||||||
if (actualPos.equals(ChunkPos.ZERO))
|
if (actualPos.equals(ChunkPos.ZERO))
|
||||||
#else
|
#else
|
||||||
if (actualPos.equals(ChunkPos.INVALID_CHUNK_POS))
|
if (actualPos.equals(ChunkPos.INVALID_CHUNK_POS))
|
||||||
@@ -349,10 +233,293 @@ public class ChunkLoader
|
|||||||
readPostPocessings(chunk, chunkData);
|
readPostPocessings(chunk, chunkData);
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData)
|
||||||
private static void logErrors(ChunkPos chunkPos, int i, String string)
|
|
||||||
{
|
{
|
||||||
LOGGER.error("Distant Horizons: Recoverable errors when loading section [" + chunkPos.x + ", " + i + ", " + chunkPos.z + "]: " + string);
|
#if MC_VER >= MC_1_18_2
|
||||||
|
#if MC_VER < MC_1_19_4
|
||||||
|
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
|
||||||
|
#else
|
||||||
|
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registries.BIOME);
|
||||||
|
#endif
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
Codec<PalettedContainer<Biome>> biomeCodec = PalettedContainer.codec(
|
||||||
|
biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
|
||||||
|
#elif MC_VER < MC_1_19_2
|
||||||
|
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
|
||||||
|
#endif
|
||||||
|
int sectionYIndex = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif
|
||||||
|
LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYIndex];
|
||||||
|
|
||||||
|
boolean isLightOn = chunkData.getBoolean("isLightOn");
|
||||||
|
boolean hasSkyLight = level.dimensionType().hasSkyLight();
|
||||||
|
ListTag tagSections = chunkData.getList("Sections", 10);
|
||||||
|
if (tagSections.isEmpty()) tagSections = chunkData.getList("sections", 10);
|
||||||
|
|
||||||
|
for (int j = 0; j < tagSections.size(); ++j)
|
||||||
|
{
|
||||||
|
CompoundTag tagSection = tagSections.getCompound(j);
|
||||||
|
int sectionYPos = tagSection.getByte("Y");
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
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 MC_VER < MC_1_17_1 sectionYPos #else level.getSectionIndexFromSectionY(sectionYPos) #endif ]
|
||||||
|
= levelChunkSection;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int sectionId = level.getSectionIndexFromSectionY(sectionYPos);
|
||||||
|
if (sectionId >= 0 && sectionId < chunkSections.length)
|
||||||
|
{
|
||||||
|
PalettedContainer<BlockState> blockStateContainer;
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
PalettedContainer<Biome> biomeContainer;
|
||||||
|
#else
|
||||||
|
PalettedContainer<Holder<Biome>> biomeContainer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
blockStateContainer = tagSection.contains("block_states", 10)
|
||||||
|
? BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagSection.getCompound("block_states")).promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
|
||||||
|
#if MC_VER < MC_1_20_6
|
||||||
|
.getOrThrow(false, LOGGER::error)
|
||||||
|
#else
|
||||||
|
.getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null))
|
||||||
|
#endif
|
||||||
|
: new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
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
|
||||||
|
|
||||||
|
biomeContainer = tagSection.contains("biomes", 10)
|
||||||
|
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
|
||||||
|
#if MC_VER < MC_1_20_6
|
||||||
|
.getOrThrow(false, LOGGER::error)
|
||||||
|
#else
|
||||||
|
.getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null))
|
||||||
|
#endif
|
||||||
|
: new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(), biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_20_1
|
||||||
|
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
|
||||||
|
#else
|
||||||
|
chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
return chunkSections;
|
||||||
|
}
|
||||||
|
private static
|
||||||
|
#if MC_VER < MC_1_20_6 ChunkStatus.ChunkType
|
||||||
|
#elif MC_VER < MC_1_21_1 ChunkType
|
||||||
|
#else ChunkType #endif
|
||||||
|
readChunkType(CompoundTag tagLevel)
|
||||||
|
{
|
||||||
|
ChunkStatus chunkStatus = ChunkStatus.byName(tagLevel.getString("Status"));
|
||||||
|
if (chunkStatus != null)
|
||||||
|
{
|
||||||
|
return chunkStatus.getChunkType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
#if MC_VER <= MC_1_20_4 ChunkStatus.ChunkType.PROTOCHUNK;
|
||||||
|
#else ChunkType.PROTOCHUNK; #endif
|
||||||
|
}
|
||||||
|
private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
|
||||||
|
{
|
||||||
|
CompoundTag tagHeightmaps = chunkData.getCompound("Heightmaps");
|
||||||
|
for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
|
||||||
|
{
|
||||||
|
String heightmap = type.getSerializationKey();
|
||||||
|
if (tagHeightmaps.contains(heightmap, 12))
|
||||||
|
chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap));
|
||||||
|
}
|
||||||
|
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
|
||||||
|
}
|
||||||
|
private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
|
||||||
|
{
|
||||||
|
ListTag tagPostProcessings = chunkData.getList("PostProcessing", 9);
|
||||||
|
for (int n = 0; n < tagPostProcessings.size(); ++n)
|
||||||
|
{
|
||||||
|
ListTag listTag3 = tagPostProcessings.getList(n);
|
||||||
|
for (int o = 0; o < listTag3.size(); ++o)
|
||||||
|
{
|
||||||
|
chunk.addPackedPostProcess(listTag3.getShort(o), n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if MC_VER >= MC_1_18_2
|
||||||
|
private static BlendingData readBlendingData(CompoundTag chunkData)
|
||||||
|
{
|
||||||
|
BlendingData blendingData = null;
|
||||||
|
if (chunkData.contains("blending_data", 10))
|
||||||
|
{
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
Dynamic<CompoundTag> blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data"));
|
||||||
|
blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial(LOGGER::error).orElse(null);
|
||||||
|
}
|
||||||
|
return blendingData;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=====================//
|
||||||
|
// read chunk lighting //
|
||||||
|
//=====================//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://minecraft.wiki/w/Chunk_format
|
||||||
|
*/
|
||||||
|
public static CombinedChunkLightStorage readLight(ChunkAccess chunk, CompoundTag chunkData)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_1_17_1
|
||||||
|
// MC 1.16 and 1.17 doesn't have the necessary NBT info
|
||||||
|
return null;
|
||||||
|
#else
|
||||||
|
|
||||||
|
CombinedChunkLightStorage combinedStorage = new CombinedChunkLightStorage(ChunkWrapper.getMinBuildHeight(chunk), ChunkWrapper.getMaxBuildHeight(chunk));
|
||||||
|
ChunkLightStorage blockLightStorage = combinedStorage.blockLightStorage;
|
||||||
|
ChunkLightStorage skyLightStorage = combinedStorage.skyLightStorage;
|
||||||
|
|
||||||
|
boolean foundSkyLight = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===================//
|
||||||
|
// get NBT tags info //
|
||||||
|
//===================//
|
||||||
|
|
||||||
|
Tag chunkSectionTags = chunkData.get("sections");
|
||||||
|
if (chunkSectionTags == null)
|
||||||
|
{
|
||||||
|
if (!lightingSectionErrorLogged)
|
||||||
|
{
|
||||||
|
lightingSectionErrorLogged = true;
|
||||||
|
LOGGER.error("No sections found for chunk at pos ["+chunk.getPos()+"] chunk data may be out of date.");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if (!(chunkSectionTags instanceof ListTag))
|
||||||
|
{
|
||||||
|
if (!lightingSectionErrorLogged)
|
||||||
|
{
|
||||||
|
lightingSectionErrorLogged = true;
|
||||||
|
LOGGER.error("Chunk section tag list have unexpected type ["+chunkSectionTags.getClass().getName()+"], expected ["+ListTag.class.getName()+"].");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ListTag chunkSectionListTag = (ListTag) chunkSectionTags;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===================//
|
||||||
|
// get lighting info //
|
||||||
|
//===================//
|
||||||
|
|
||||||
|
for (int sectionIndex = 0; sectionIndex < chunkSectionListTag.size(); sectionIndex++)
|
||||||
|
{
|
||||||
|
Tag chunkSectionTag = chunkSectionListTag.get(sectionIndex);
|
||||||
|
if (!(chunkSectionTag instanceof CompoundTag))
|
||||||
|
{
|
||||||
|
if (!lightingSectionErrorLogged)
|
||||||
|
{
|
||||||
|
lightingSectionErrorLogged = true;
|
||||||
|
LOGGER.error("Chunk section tag has an unexpected type ["+chunkSectionTag.getClass().getName()+"], expected ["+CompoundTag.class.getName()+"].");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
CompoundTag chunkSectionCompoundTag = (CompoundTag) chunkSectionTag;
|
||||||
|
|
||||||
|
|
||||||
|
// if null all lights = 0
|
||||||
|
byte[] blockLightNibbleArray = chunkSectionCompoundTag.getByteArray("BlockLight");
|
||||||
|
byte[] skyLightNibbleArray = chunkSectionCompoundTag.getByteArray("SkyLight");
|
||||||
|
|
||||||
|
// if any sky light was found then all lights above will be max brightness
|
||||||
|
if (skyLightNibbleArray.length != 0)
|
||||||
|
{
|
||||||
|
foundSkyLight = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++)
|
||||||
|
{
|
||||||
|
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
|
||||||
|
{
|
||||||
|
// chunk sections are also 16 blocks tall
|
||||||
|
for (int relY = 0; relY < LodUtil.CHUNK_WIDTH; relY++)
|
||||||
|
{
|
||||||
|
int blockPosIndex = relY*16*16 + relZ*16 + relX;
|
||||||
|
byte blockLight = (blockLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(blockLightNibbleArray, blockPosIndex);
|
||||||
|
byte skyLight = (skyLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(skyLightNibbleArray, blockPosIndex);
|
||||||
|
if (skyLightNibbleArray.length == 0 && foundSkyLight)
|
||||||
|
{
|
||||||
|
skyLight = LodUtil.MAX_MC_LIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int y = relY + (sectionIndex * LodUtil.CHUNK_WIDTH) + ChunkWrapper.getMinBuildHeight(chunk);
|
||||||
|
blockLightStorage.set(relX, y, relZ, blockLight);
|
||||||
|
skyLightStorage.set(relX, y, relZ, skyLight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return combinedStorage;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/** source: https://minecraft.wiki/w/Chunk_format#Block_Format */
|
||||||
|
private static byte getNibbleAtIndex(byte[] arr, int index)
|
||||||
|
{
|
||||||
|
if (index % 2 == 0)
|
||||||
|
{
|
||||||
|
return (byte)(arr[index/2] & 0x0F);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (byte)((arr[index/2]>>4) & 0x0F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void logBlockDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Unable to deserialize blocks for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+message+"]. This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||||
|
}
|
||||||
|
private static void logBiomeDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Unable to deserialize biomes for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+message+"]. This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper classes //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
public static class CombinedChunkLightStorage
|
||||||
|
{
|
||||||
|
public ChunkLightStorage blockLightStorage;
|
||||||
|
public ChunkLightStorage skyLightStorage;
|
||||||
|
|
||||||
|
public CombinedChunkLightStorage(int minY, int maxY)
|
||||||
|
{
|
||||||
|
this.blockLightStorage = ChunkLightStorage.createBlockLightStorage(minY, maxY);
|
||||||
|
this.skyLightStorage = ChunkLightStorage.createSkyLightStorage(minY, maxY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_21_1
|
||||||
|
|
||||||
|
import net.minecraft.server.level.GenerationChunkHolder;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
|
||||||
|
public class DhGenerationChunkHolder extends GenerationChunkHolder
|
||||||
|
{
|
||||||
|
|
||||||
|
public DhGenerationChunkHolder(ChunkPos pos)
|
||||||
|
{
|
||||||
|
super(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTicketLevel() { return 0; }
|
||||||
|
@Override
|
||||||
|
public int getQueueLevel() { return 0; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
+46
-6
@@ -22,7 +22,7 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
|||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
@@ -59,7 +59,13 @@ import net.minecraft.world.level.lighting.LevelLightEngine;
|
|||||||
#if MC_VER <= MC_1_20_4
|
#if MC_VER <= MC_1_20_4
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
#else
|
#else
|
||||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
import net.minecraft.world.level.chunk.status.*;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_21_1
|
||||||
|
import net.minecraft.util.StaticCache2D;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import net.minecraft.server.level.GenerationChunkHolder;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -71,7 +77,7 @@ public class DhLitWorldGenRegion extends WorldGenRegion
|
|||||||
|
|
||||||
|
|
||||||
public final DummyLightEngine lightEngine;
|
public final DummyLightEngine lightEngine;
|
||||||
public final BatchGenerationEnvironment.EmptyChunkGenerator generator;
|
public final BatchGenerationEnvironment.IEmptyChunkGeneratorFunc generator;
|
||||||
public final int writeRadius;
|
public final int writeRadius;
|
||||||
public final int size;
|
public final int size;
|
||||||
|
|
||||||
@@ -112,11 +118,29 @@ public class DhLitWorldGenRegion extends WorldGenRegion
|
|||||||
|
|
||||||
|
|
||||||
public DhLitWorldGenRegion(
|
public DhLitWorldGenRegion(
|
||||||
|
int centerChunkX, int centerChunkZ,
|
||||||
|
ChunkAccess centerChunk,
|
||||||
ServerLevel serverLevel, DummyLightEngine lightEngine,
|
ServerLevel serverLevel, DummyLightEngine lightEngine,
|
||||||
List<ChunkAccess> chunkList, ChunkStatus chunkStatus, int writeRadius,
|
List<ChunkAccess> chunkList, ChunkStatus chunkStatus, int writeRadius,
|
||||||
BatchGenerationEnvironment.EmptyChunkGenerator generator)
|
BatchGenerationEnvironment.IEmptyChunkGeneratorFunc generator)
|
||||||
{
|
{
|
||||||
super(serverLevel, chunkList #if MC_VER >= MC_1_17_1 , chunkStatus, writeRadius #endif );
|
#if MC_VER == MC_1_16_5
|
||||||
|
super(serverLevel, chunkList);
|
||||||
|
#elif MC_VER < MC_1_21_1
|
||||||
|
super(serverLevel, chunkList, chunkStatus, writeRadius);
|
||||||
|
#else
|
||||||
|
super(serverLevel,
|
||||||
|
StaticCache2D.create(
|
||||||
|
centerChunkX, centerChunkZ,
|
||||||
|
writeRadius * 2, (x,z) -> new DhGenerationChunkHolder(new ChunkPos(x, z))),
|
||||||
|
new ChunkStep(chunkStatus,
|
||||||
|
// reverse is needed because MC uses the index of the chunkStatus to determine how many items are in the list instead of the actual list count
|
||||||
|
new ChunkDependencies(ImmutableList.copyOf(ChunkStatus.getStatusList()).reverse()),
|
||||||
|
new ChunkDependencies(ImmutableList.copyOf(ChunkStatus.getStatusList()).reverse()),
|
||||||
|
writeRadius, (WorldGenContext var1, ChunkStep var2, StaticCache2D<GenerationChunkHolder> var3, ChunkAccess var4) -> null),
|
||||||
|
centerChunk);
|
||||||
|
|
||||||
|
#endif
|
||||||
this.firstPos = chunkList.get(0).getPos();
|
this.firstPos = chunkList.get(0).getPos();
|
||||||
this.generator = generator;
|
this.generator = generator;
|
||||||
this.lightEngine = lightEngine;
|
this.lightEngine = lightEngine;
|
||||||
@@ -210,6 +234,22 @@ public class DhLitWorldGenRegion extends WorldGenRegion
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This needs to be manually overridden to make sure Lithium 0.11.2 and lower
|
||||||
|
* don't try to get null chunks. <br><br>
|
||||||
|
*
|
||||||
|
* Problematic Lithium code was removed in 0.13.0 (MC 1.21.1) and higher: <br>
|
||||||
|
* https://github.com/CaffeineMC/lithium-fabric/commit/b7cfd53a1ed0197e1d13dea2799b898eb52ecab3
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public BlockState getBlockState(BlockPos blockPos)
|
||||||
|
{
|
||||||
|
int chunkX = SectionPos.blockToSectionCoord(blockPos.getX());
|
||||||
|
int chunkZ = SectionPos.blockToSectionCoord(blockPos.getZ());
|
||||||
|
return this.getChunk(chunkX, chunkZ).getBlockState(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
/** Skip BlockEntity stuff. They aren't needed for our use case. */
|
/** Skip BlockEntity stuff. They aren't needed for our use case. */
|
||||||
@Override
|
@Override
|
||||||
public boolean addFreshEntity(@NotNull Entity entity) { return true; }
|
public boolean addFreshEntity(@NotNull Entity entity) { return true; }
|
||||||
@@ -280,7 +320,7 @@ public class DhLitWorldGenRegion extends WorldGenRegion
|
|||||||
private ChunkAccess getChunkAccess(int chunkX, int chunkZ, ChunkStatus chunkStatus, boolean returnNonNull)
|
private ChunkAccess getChunkAccess(int chunkX, int chunkZ, ChunkStatus chunkStatus, boolean returnNonNull)
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = this.superHasChunk(chunkX, chunkZ) ? this.superGetChunk(chunkX, chunkZ) : null;
|
ChunkAccess chunk = this.superHasChunk(chunkX, chunkZ) ? this.superGetChunk(chunkX, chunkZ) : null;
|
||||||
if (chunk != null && chunk.getStatus().isOrAfter(chunkStatus))
|
if (chunk != null && ChunkWrapper.getStatus(chunk).isOrAfter(chunkStatus))
|
||||||
{
|
{
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-8
@@ -56,29 +56,44 @@ public final class StepBiomes
|
|||||||
List<ChunkWrapper> chunkWrappers)
|
List<ChunkWrapper> chunkWrappers)
|
||||||
{
|
{
|
||||||
|
|
||||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
|
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
|
||||||
|
|
||||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
if (chunk.getStatus().isOrAfter(STATUS)) continue;
|
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||||
((ProtoChunk) chunk).setStatus(STATUS);
|
{
|
||||||
chunksToDo.add(chunk);
|
// this chunk has already generated this step
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (chunk instanceof ProtoChunk)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
((ProtoChunk) chunk).setStatus(STATUS);
|
||||||
|
#else
|
||||||
|
((ProtoChunk) chunk).setPersistedStatus(STATUS);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
chunksToDo.add(chunk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ChunkAccess chunk : chunksToDo)
|
for (ChunkAccess chunk : chunksToDo)
|
||||||
{
|
{
|
||||||
// System.out.println("StepBiomes: "+chunk.getPos());
|
// System.out.println("StepBiomes: "+chunk.getPos());
|
||||||
#if MC_VER < MC_1_18_2
|
#if MC_VER < MC_1_18_2
|
||||||
environment.params.generator.createBiomes(environment.params.biomes, chunk);
|
this.environment.params.generator.createBiomes(this.environment.params.biomes, chunk);
|
||||||
#elif MC_VER < MC_1_19_2
|
#elif MC_VER < MC_1_19_2
|
||||||
chunk = environment.joinSync(environment.params.generator.createBiomes(environment.params.biomes, Runnable::run, Blender.of(worldGenRegion),
|
chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.biomes, Runnable::run, Blender.of(worldGenRegion),
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
#elif MC_VER < MC_1_19_4
|
#elif MC_VER < MC_1_19_4
|
||||||
chunk = environment.joinSync(environment.params.generator.createBiomes(environment.params.biomes, Runnable::run, environment.params.randomState, Blender.of(worldGenRegion),
|
chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.biomes, Runnable::run, this.environment.params.randomState, Blender.of(worldGenRegion),
|
||||||
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
|
#elif MC_VER < MC_1_21_1
|
||||||
|
chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(Runnable::run, this.environment.params.randomState, Blender.of(worldGenRegion),
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
#else
|
#else
|
||||||
chunk = environment.joinSync(environment.params.generator.createBiomes(Runnable::run, environment.params.randomState, Blender.of(worldGenRegion),
|
chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.randomState, Blender.of(worldGenRegion),
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-4
@@ -59,14 +59,18 @@ public final class StepFeatures
|
|||||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
if (chunk.getStatus().isOrAfter(STATUS))
|
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||||
{
|
{
|
||||||
|
// this chunk has already generated this step
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else if (chunk instanceof ProtoChunk)
|
||||||
if (chunk instanceof ProtoChunk)
|
|
||||||
{
|
{
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
((ProtoChunk) chunk).setStatus(STATUS);
|
((ProtoChunk) chunk).setStatus(STATUS);
|
||||||
|
#else
|
||||||
|
((ProtoChunk) chunk).setPersistedStatus(STATUS);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -76,7 +80,7 @@ public final class StepFeatures
|
|||||||
worldGenRegion.setOverrideCenter(chunk.getPos());
|
worldGenRegion.setOverrideCenter(chunk.getPos());
|
||||||
environment.params.generator.applyBiomeDecoration(worldGenRegion, tParams.structFeat);
|
environment.params.generator.applyBiomeDecoration(worldGenRegion, tParams.structFeat);
|
||||||
#else
|
#else
|
||||||
if (worldGenRegion.hasChunk(chunkWrapper.getChunkPos().x, chunkWrapper.getChunkPos().z))
|
if (worldGenRegion.hasChunk(chunkWrapper.getChunkPos().getX(), chunkWrapper.getChunkPos().getZ()))
|
||||||
{
|
{
|
||||||
this.environment.params.generator.applyBiomeDecoration(worldGenRegion, chunk, tParams.structFeat.forWorldGenRegion(worldGenRegion));
|
this.environment.params.generator.applyBiomeDecoration(worldGenRegion, chunk, tParams.structFeat.forWorldGenRegion(worldGenRegion));
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-6
@@ -58,13 +58,21 @@ public final class StepNoise
|
|||||||
List<ChunkWrapper> chunkWrappers)
|
List<ChunkWrapper> chunkWrappers)
|
||||||
{
|
{
|
||||||
|
|
||||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
|
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
|
||||||
|
|
||||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
if (chunk.getStatus().isOrAfter(STATUS)) continue;
|
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
((ProtoChunk) chunk).setStatus(STATUS);
|
((ProtoChunk) chunk).setStatus(STATUS);
|
||||||
|
#else
|
||||||
|
((ProtoChunk) chunk).setPersistedStatus(STATUS);
|
||||||
|
#endif
|
||||||
chunksToDo.add(chunk);
|
chunksToDo.add(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,15 +80,18 @@ public final class StepNoise
|
|||||||
{
|
{
|
||||||
// System.out.println("StepNoise: "+chunk.getPos());
|
// System.out.println("StepNoise: "+chunk.getPos());
|
||||||
#if MC_VER < MC_1_17_1
|
#if MC_VER < MC_1_17_1
|
||||||
environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk);
|
this.environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk);
|
||||||
#elif MC_VER < MC_1_18_2
|
#elif MC_VER < MC_1_18_2
|
||||||
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run,
|
chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run,
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
#elif MC_VER < MC_1_19_2
|
#elif MC_VER < MC_1_19_2
|
||||||
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion),
|
chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion),
|
||||||
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
|
#elif MC_VER < MC_1_21_1
|
||||||
|
chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), this.environment.params.randomState,
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
#else
|
#else
|
||||||
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), environment.params.randomState,
|
chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Blender.of(worldGenRegion), this.environment.params.randomState,
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
#endif
|
#endif
|
||||||
UncheckedInterruptedException.throwIfInterrupted();
|
UncheckedInterruptedException.throwIfInterrupted();
|
||||||
|
|||||||
+14
-3
@@ -59,9 +59,20 @@ public final class StepStructureReference
|
|||||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
if (chunk.getStatus().isOrAfter(STATUS)) continue;
|
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||||
((ProtoChunk) chunk).setStatus(STATUS);
|
{
|
||||||
chunksToDo.add(chunk);
|
// this chunk has already generated this step
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (chunk instanceof ProtoChunk)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
((ProtoChunk) chunk).setStatus(STATUS);
|
||||||
|
#else
|
||||||
|
((ProtoChunk) chunk).setPersistedStatus(STATUS);
|
||||||
|
#endif
|
||||||
|
chunksToDo.add(chunk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ChunkAccess chunk : chunksToDo)
|
for (ChunkAccess chunk : chunksToDo)
|
||||||
|
|||||||
+13
-4
@@ -76,20 +76,29 @@ public final class StepStructureStart
|
|||||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
if (!chunk.getStatus().isOrAfter(STATUS))
|
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||||
{
|
{
|
||||||
|
// this chunk has already generated this step
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (chunk instanceof ProtoChunk)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
((ProtoChunk) chunk).setStatus(STATUS);
|
((ProtoChunk) chunk).setStatus(STATUS);
|
||||||
|
#else
|
||||||
|
((ProtoChunk) chunk).setPersistedStatus(STATUS);
|
||||||
|
#endif
|
||||||
chunksToDo.add(chunk);
|
chunksToDo.add(chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
if (environment.params.worldGenSettings.generateFeatures())
|
if (this.environment.params.worldGenSettings.generateFeatures())
|
||||||
{
|
{
|
||||||
#elif MC_VER < MC_1_19_4
|
#elif MC_VER < MC_1_19_4
|
||||||
if (environment.params.worldGenSettings.generateStructures()) {
|
if (this.environment.params.worldGenSettings.generateStructures()) {
|
||||||
#else
|
#else
|
||||||
if (environment.params.worldOptions.generateStructures())
|
if (this.environment.params.worldOptions.generateStructures())
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
for (ChunkAccess chunk : chunksToDo)
|
for (ChunkAccess chunk : chunksToDo)
|
||||||
|
|||||||
+15
-3
@@ -58,9 +58,21 @@ public final class StepSurface
|
|||||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
if (chunk.getStatus().isOrAfter(STATUS)) continue;
|
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||||
((ProtoChunk) chunk).setStatus(STATUS);
|
{
|
||||||
chunksToDo.add(chunk);
|
// this chunk has already generated this step
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (chunk instanceof ProtoChunk)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
((ProtoChunk) chunk).setStatus(STATUS);
|
||||||
|
#else
|
||||||
|
((ProtoChunk) chunk).setPersistedStatus(STATUS);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
chunksToDo.add(chunk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ChunkAccess chunk : chunksToDo)
|
for (ChunkAccess chunk : chunksToDo)
|
||||||
|
|||||||
@@ -47,4 +47,7 @@ accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite frames
|
|||||||
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite framesY [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;
|
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite mainImage [Lcom/mojang/blaze3d/platform/NativeImage;
|
||||||
|
|
||||||
|
# DimensionTypeWrapper workaround
|
||||||
|
accessible field net/minecraft/world/level/dimension/DimensionType effectsLocation Lnet/minecraft/resources/ResourceLocation;
|
||||||
|
|
||||||
extendable class com/mojang/math/Matrix4f
|
extendable class com/mojang/math/Matrix4f
|
||||||
|
|||||||
+1
-1
Submodule coreSubProjects updated: 76f28e648c...7cd1a37914
+13
-2
@@ -5,19 +5,25 @@ plugins {
|
|||||||
loom {
|
loom {
|
||||||
accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
||||||
|
|
||||||
|
// Custom logging
|
||||||
|
log4jConfigs.from(file("log4j-dev.xml"))
|
||||||
|
|
||||||
// "runs" isn't required, but when we do need it then it can be useful
|
// "runs" isn't required, but when we do need it then it can be useful
|
||||||
runs {
|
runs {
|
||||||
client {
|
client {
|
||||||
client()
|
client()
|
||||||
setConfigName("Fabric Client")
|
setConfigName("Fabric Client")
|
||||||
ideConfigGenerated(true)
|
ideConfigGenerated(true)
|
||||||
runDir("../run")
|
runDir("../run/client")
|
||||||
|
vmArgs("-Dio.netty.leakDetection.level=advanced")
|
||||||
|
programArgs("--username", "Dev")
|
||||||
}
|
}
|
||||||
server {
|
server {
|
||||||
server()
|
server()
|
||||||
setConfigName("Fabric Server")
|
setConfigName("Fabric Server")
|
||||||
ideConfigGenerated(true)
|
ideConfigGenerated(true)
|
||||||
runDir("../run")
|
runDir("../run/server")
|
||||||
|
vmArgs("-Dio.netty.leakDetection.level=advanced")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,6 +75,11 @@ dependencies {
|
|||||||
addModJar(fabricApi.module("fabric-events-interaction-v0", rootProject.fabric_api_version))
|
addModJar(fabricApi.module("fabric-events-interaction-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-rendering-v1", rootProject.fabric_api_version)) // TODO: Remove this as it is only needed in 1 line (FabricClientProxy)
|
||||||
addModJar(fabricApi.module("fabric-networking-api-v1", rootProject.fabric_api_version))
|
addModJar(fabricApi.module("fabric-networking-api-v1", rootProject.fabric_api_version))
|
||||||
|
addModJar(fabricApi.module("fabric-entity-events-v1", rootProject.fabric_api_version))
|
||||||
|
if (minecraft_version >= "1.19.2")
|
||||||
|
addModJar(fabricApi.module("fabric-command-api-v2", rootProject.fabric_api_version))
|
||||||
|
else // < 1.19.2
|
||||||
|
addModJar(fabricApi.module("fabric-command-api-v1", rootProject.fabric_api_version))
|
||||||
|
|
||||||
// used by mod menu in MC 1.20.6+
|
// used by mod menu in MC 1.20.6+
|
||||||
addModJar(fabricApi.module("fabric-screen-api-v1", rootProject.fabric_api_version))
|
addModJar(fabricApi.module("fabric-screen-api-v1", rootProject.fabric_api_version))
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Configuration name="Dev" monitorInterval="10">
|
||||||
|
<Loggers>
|
||||||
|
<Logger name="com.seibel.distanthorizons.core.network" level="trace" additivity="false">
|
||||||
|
<AppenderRef ref="DebugFile" level="${sys:fabric.log.debug.level:-debug}" />
|
||||||
|
<AppenderRef ref="SysOut" />
|
||||||
|
<AppenderRef ref="LatestFile" level="${sys:fabric.log.level:-info}" />
|
||||||
|
<AppenderRef ref="ServerGuiConsole" />
|
||||||
|
</Logger>
|
||||||
|
</Loggers>
|
||||||
|
</Configuration>
|
||||||
@@ -19,9 +19,8 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.fabric;
|
package com.seibel.distanthorizons.fabric;
|
||||||
|
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
||||||
|
import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
|
||||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
@@ -29,39 +28,44 @@ import com.mojang.blaze3d.platform.InputConstants;
|
|||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
import com.seibel.distanthorizons.fabric.wrappers.modAccessor.SodiumAccessor;
|
import com.seibel.distanthorizons.fabric.wrappers.modAccessor.SodiumAccessor;
|
||||||
//import io.netty.buffer.ByteBuf;
|
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents;
|
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.event.lifecycle.v1.ClientTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
||||||
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
|
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
|
||||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.screens.TitleScreen;
|
import net.minecraft.client.gui.screens.TitleScreen;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_20_6
|
||||||
|
import com.seibel.distanthorizons.common.CommonPacketPayload;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||||
|
#else
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_4
|
#if MC_VER < MC_1_19_4
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
#endif
|
#endif
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.phys.HitResult;
|
import net.minecraft.world.phys.HitResult;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,6 +94,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
* Registers Fabric Events
|
* Registers Fabric Events
|
||||||
* @author Ran
|
* @author Ran
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void registerEvents()
|
public void registerEvents()
|
||||||
{
|
{
|
||||||
LOGGER.info("Registering Fabric Client Events");
|
LOGGER.info("Registering Fabric Client Events");
|
||||||
@@ -118,11 +123,15 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
// ClientChunkLoadEvent
|
// ClientChunkLoadEvent
|
||||||
ClientChunkEvents.CHUNK_LOAD.register((level, chunk) ->
|
ClientChunkEvents.CHUNK_LOAD.register((level, chunk) ->
|
||||||
{
|
{
|
||||||
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level);
|
if (MC.clientConnectedToDedicatedServer())
|
||||||
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
|
{
|
||||||
|
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level);
|
||||||
|
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// (kinda) block break event
|
// (kinda) block break event
|
||||||
|
// Since fabric doesn't have a client-side break-block API event, this is the next best thing
|
||||||
AttackBlockCallback.EVENT.register((player, level, interactionHand, blockPos, direction) ->
|
AttackBlockCallback.EVENT.register((player, level, interactionHand, blockPos, direction) ->
|
||||||
{
|
{
|
||||||
// if we have access to the server, use the chunk save event instead
|
// if we have access to the server, use the chunk save event instead
|
||||||
@@ -130,17 +139,26 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
{
|
{
|
||||||
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(blockPos.getX(), blockPos.getZ()))
|
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(blockPos.getX(), blockPos.getZ()))
|
||||||
{
|
{
|
||||||
// Since fabric doesn't have a client-side break-block API event, this is the next best thing
|
// executor to prevent locking up the render/event thread
|
||||||
ChunkAccess chunk = level.getChunk(blockPos);
|
// if the getChunk() takes longer than expected
|
||||||
if (chunk != null)
|
// (which can be caused by certain mods)
|
||||||
|
ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
|
||||||
|
if (executor != null)
|
||||||
{
|
{
|
||||||
//LOGGER.trace("attack block at blockPos: " + blockPos);
|
executor.execute(() ->
|
||||||
|
{
|
||||||
|
ChunkAccess chunk = level.getChunk(blockPos);
|
||||||
|
if (chunk != null)
|
||||||
|
{
|
||||||
|
//LOGGER.trace("attack block at blockPos: " + blockPos);
|
||||||
|
|
||||||
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
|
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
|
||||||
SharedApi.INSTANCE.chunkBlockChangedEvent(
|
SharedApi.INSTANCE.chunkBlockChangedEvent(
|
||||||
new ChunkWrapper(chunk, level, wrappedLevel),
|
new ChunkWrapper(chunk, level, wrappedLevel),
|
||||||
wrappedLevel
|
wrappedLevel
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,27 +168,37 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
});
|
});
|
||||||
|
|
||||||
// (kinda) block place event
|
// (kinda) block place event
|
||||||
|
// Since fabric doesn't have a client-side place-block API event, this is the next best thing
|
||||||
UseBlockCallback.EVENT.register((player, level, hand, hitResult) ->
|
UseBlockCallback.EVENT.register((player, level, hand, hitResult) ->
|
||||||
{
|
{
|
||||||
// if we have access to the server, use the chunk save event instead
|
// if we have access to the server, use the chunk save event instead
|
||||||
if (MC.clientConnectedToDedicatedServer())
|
if (MC.clientConnectedToDedicatedServer())
|
||||||
{
|
{
|
||||||
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(hitResult.getBlockPos().getX(), hitResult.getBlockPos().getZ()))
|
if (hitResult.getType() == HitResult.Type.BLOCK
|
||||||
|
&& !hitResult.isInside())
|
||||||
{
|
{
|
||||||
// Since fabric doesn't have a client-side place-block API event, this is the next best thing
|
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(hitResult.getBlockPos().getX(), hitResult.getBlockPos().getZ()))
|
||||||
if (hitResult.getType() == HitResult.Type.BLOCK
|
|
||||||
&& !hitResult.isInside())
|
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = level.getChunk(hitResult.getBlockPos());
|
// executor to prevent locking up the render/event thread
|
||||||
if (chunk != null)
|
// if the getChunk() takes longer than expected
|
||||||
|
// (which can be caused by certain mods)
|
||||||
|
ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
|
||||||
|
if (executor != null)
|
||||||
{
|
{
|
||||||
//LOGGER.trace("use block at blockPos: " + hitResult.getBlockPos());
|
executor.execute(() ->
|
||||||
|
{
|
||||||
|
ChunkAccess chunk = level.getChunk(hitResult.getBlockPos());
|
||||||
|
if (chunk != null)
|
||||||
|
{
|
||||||
|
//LOGGER.trace("use block at blockPos: " + hitResult.getBlockPos());
|
||||||
|
|
||||||
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
|
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
|
||||||
SharedApi.INSTANCE.chunkBlockChangedEvent(
|
SharedApi.INSTANCE.chunkBlockChangedEvent(
|
||||||
new ChunkWrapper(chunk, level, wrappedLevel),
|
new ChunkWrapper(chunk, level, wrappedLevel),
|
||||||
wrappedLevel
|
wrappedLevel
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,14 +209,6 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Client Chunk Save
|
|
||||||
ClientChunkEvents.CHUNK_UNLOAD.register((level, chunk) ->
|
|
||||||
{
|
|
||||||
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level);
|
|
||||||
SharedApi.INSTANCE.chunkUnloadEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==============//
|
//==============//
|
||||||
// render event //
|
// render event //
|
||||||
@@ -208,7 +228,12 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
this.clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()),
|
this.clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()),
|
||||||
modelViewMatrix,
|
modelViewMatrix,
|
||||||
projectionMatrix,
|
projectionMatrix,
|
||||||
renderContext.tickDelta());
|
#if MC_VER < MC_1_21_1
|
||||||
|
renderContext.tickDelta()
|
||||||
|
#else
|
||||||
|
renderContext.tickCounter().getGameTimeDeltaTicks()
|
||||||
|
#endif
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Debug keyboard event
|
// Debug keyboard event
|
||||||
@@ -227,17 +252,29 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
// networking event //
|
// networking event //
|
||||||
//==================//
|
//==================//
|
||||||
|
|
||||||
// ClientPlayNetworking.registerGlobalReceiver(new ResourceLocation(ModInfo.NETWORKING_RESOURCE_NAMESPACE, ModInfo.MULTIVERSE_PLUGIN_NAMESPACE),
|
#if MC_VER >= MC_1_20_6
|
||||||
// (Minecraft client, ClientPacketListener handler, FriendlyByteBuf friendlyByteBuf, PacketSender responseSender) ->
|
PayloadTypeRegistry.playC2S().register(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec());
|
||||||
// {
|
PayloadTypeRegistry.playS2C().register(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec());
|
||||||
// // converting to a ByteBuf is necessary otherwise Fabric will complain when the game boots
|
ClientPlayNetworking.registerGlobalReceiver(CommonPacketPayload.TYPE, (payload, context) ->
|
||||||
// ByteBuf nettyByteBuf = friendlyByteBuf.asByteBuf();
|
{
|
||||||
//
|
if (payload.message() == null)
|
||||||
// // remove the Bukkit/Forge packet ID byte
|
{
|
||||||
// nettyByteBuf.readByte();
|
return;
|
||||||
//
|
}
|
||||||
// ClientApi.INSTANCE.serverMessageReceived(nettyByteBuf);
|
ClientApi.INSTANCE.pluginMessageReceived(payload.message());
|
||||||
// });
|
});
|
||||||
|
#else
|
||||||
|
ClientPlayNetworking.registerGlobalReceiver(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE, (client, handler, buffer, packetSender) ->
|
||||||
|
{
|
||||||
|
// Forge packet ID
|
||||||
|
buffer.readByte();
|
||||||
|
NetworkMessage message = AbstractPluginPacketSender.decodeMessage(buffer);
|
||||||
|
if (message != null)
|
||||||
|
{
|
||||||
|
ClientApi.INSTANCE.pluginMessageReceived(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onKeyInput()
|
public void onKeyInput()
|
||||||
@@ -266,14 +303,14 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
// Diff and trigger events
|
// Diff and trigger events
|
||||||
for (int keyCode : currentKeyDown)
|
for (int keyCode : currentKeyDown)
|
||||||
{
|
{
|
||||||
if (!previouslyPressKeyCodes.contains(keyCode))
|
if (!this.previouslyPressKeyCodes.contains(keyCode))
|
||||||
{
|
{
|
||||||
ClientApi.INSTANCE.keyPressedEvent(keyCode);
|
ClientApi.INSTANCE.keyPressedEvent(keyCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the set
|
// Update the set
|
||||||
previouslyPressKeyCodes = currentKeyDown;
|
this.previouslyPressKeyCodes = currentKeyDown;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,7 @@ import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
|||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.*;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.*;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import com.seibel.distanthorizons.fabric.wrappers.modAccessor.*;
|
import com.seibel.distanthorizons.fabric.wrappers.modAccessor.*;
|
||||||
@@ -40,6 +41,12 @@ import net.minecraft.resources.ResourceLocation;
|
|||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_19_2
|
||||||
|
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||||
|
#else // < 1.19.2
|
||||||
|
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||||
|
#endif
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@@ -51,14 +58,22 @@ import java.util.function.Consumer;
|
|||||||
*/
|
*/
|
||||||
public class FabricMain extends AbstractModInitializer implements ClientModInitializer, DedicatedServerModInitializer
|
public class FabricMain extends AbstractModInitializer implements ClientModInitializer, DedicatedServerModInitializer
|
||||||
{
|
{
|
||||||
private static final ResourceLocation INITIAL_PHASE = ResourceLocation.tryParse("distanthorizons:dedicated_server_initial");
|
#if MC_VER >= MC_1_21_1
|
||||||
|
private static final ResourceLocation INITIAL_PHASE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.DEDICATED_SERVER_INITIAL_PATH);
|
||||||
|
#else
|
||||||
|
private static final ResourceLocation INITIAL_PHASE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.DEDICATED_SERVER_INITIAL_PATH);
|
||||||
|
#endif
|
||||||
|
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createInitialBindings() { SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); }
|
protected void createInitialBindings()
|
||||||
|
{
|
||||||
|
SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
|
||||||
|
SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new FabricPluginPacketSender());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IEventProxy createClientProxy() { return new FabricClientProxy(); }
|
protected IEventProxy createClientProxy() { return new FabricClientProxy(); }
|
||||||
@@ -102,7 +117,12 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler) { }
|
protected void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler)
|
||||||
|
{
|
||||||
|
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess #if MC_VER >= MC_1_19_2 , environment #endif ) -> {
|
||||||
|
eventHandler.accept(dispatcher);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void subscribeClientStartedEvent(Runnable eventHandler) { ClientLifecycleEvents.CLIENT_STARTED.register((mc) -> eventHandler.run()); }
|
protected void subscribeClientStartedEvent(Runnable eventHandler) { ClientLifecycleEvents.CLIENT_STARTED.register((mc) -> eventHandler.run()); }
|
||||||
@@ -120,15 +140,21 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
|
|||||||
SingletonInjector.INSTANCE.runDelayedSetup();
|
SingletonInjector.INSTANCE.runDelayedSetup();
|
||||||
|
|
||||||
if (Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get() && SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("bclib"))
|
if (Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get() && SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("bclib"))
|
||||||
|
{
|
||||||
ModAccessorInjector.INSTANCE.get(IBCLibAccessor.class).setRenderCustomFog(false); // Remove BCLib's fog
|
ModAccessorInjector.INSTANCE.get(IBCLibAccessor.class).setRenderCustomFog(false); // Remove BCLib's fog
|
||||||
|
}
|
||||||
|
|
||||||
#if MC_VER >= MC_1_20_1
|
#if MC_VER >= MC_1_20_1
|
||||||
if (SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("sodium"))
|
if (SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("sodium"))
|
||||||
ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class).setFogOcclusion(false); // FIXME: This is a tmp fix for sodium 0.5.0, and 0.5.1. This is fixed in sodium 0.5.2
|
{
|
||||||
|
ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class).setFogOcclusion(false);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ConfigBase.INSTANCE == null)
|
if (ConfigBase.INSTANCE == null)
|
||||||
|
{
|
||||||
throw new IllegalStateException("Config was not initialized. Make sure to call LodCommonMain.initConfig() before calling this method.");
|
throw new IllegalStateException("Config was not initialized. Make sure to call LodCommonMain.initConfig() before calling this method.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.seibel.distanthorizons.fabric;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
|
||||||
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_20_6
|
||||||
|
import com.seibel.distanthorizons.common.CommonPacketPayload;
|
||||||
|
#else // < 1.20.6
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public class FabricPluginPacketSender extends AbstractPluginPacketSender
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void sendPluginPacketClient(NetworkMessage message)
|
||||||
|
{
|
||||||
|
#if MC_VER >= MC_1_20_6
|
||||||
|
ClientPlayNetworking.send(new CommonPacketPayload(message));
|
||||||
|
#else // < 1.20.6
|
||||||
|
FriendlyByteBuf buffer = PacketByteBufs.create();
|
||||||
|
// Forge packet ID
|
||||||
|
buffer.writeByte(0);
|
||||||
|
AbstractPluginPacketSender.encodeMessage(buffer, message);
|
||||||
|
ClientPlayNetworking.send(WRAPPER_PACKET_RESOURCE, buffer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPluginPacketServer(ServerPlayer serverPlayer, NetworkMessage message)
|
||||||
|
{
|
||||||
|
#if MC_VER >= MC_1_20_6
|
||||||
|
ServerPlayNetworking.send(serverPlayer, new CommonPacketPayload(message));
|
||||||
|
#else // < 1.20.6
|
||||||
|
FriendlyByteBuf buffer = PacketByteBufs.create();
|
||||||
|
// Forge packet ID
|
||||||
|
buffer.writeByte(0);
|
||||||
|
AbstractPluginPacketSender.encodeMessage(buffer, message);
|
||||||
|
ServerPlayNetworking.send(serverPlayer, WRAPPER_PACKET_RESOURCE, buffer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.seibel.distanthorizons.fabric;
|
package com.seibel.distanthorizons.fabric;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.DhApiEventRegister;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent;
|
||||||
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
||||||
@@ -10,11 +12,14 @@ import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
|||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
|
import com.seibel.distanthorizons.fabric.testing.TestWorldGenBindingEvent;
|
||||||
|
import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents;
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
|
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.ServerLifecycleEvents;
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
|
||||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.screens.TitleScreen;
|
import net.minecraft.client.gui.screens.TitleScreen;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
@@ -22,6 +27,14 @@ import net.minecraft.server.level.ServerLevel;
|
|||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_20_6
|
||||||
|
import com.seibel.distanthorizons.common.CommonPacketPayload;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||||
|
#else
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
|
||||||
|
import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
|
||||||
|
#endif
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,7 +64,7 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
|
|
||||||
private boolean isValidTime()
|
private boolean isValidTime()
|
||||||
{
|
{
|
||||||
if (isDedicated)
|
if (this.isDedicated)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -65,6 +78,7 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
private ServerPlayerWrapper getServerPlayerWrapper(ServerPlayer player) { return ServerPlayerWrapper.getWrapper(player); }
|
private ServerPlayerWrapper getServerPlayerWrapper(ServerPlayer player) { return ServerPlayerWrapper.getWrapper(player); }
|
||||||
|
|
||||||
/** Registers Fabric Events */
|
/** Registers Fabric Events */
|
||||||
|
@Override
|
||||||
public void registerEvents()
|
public void registerEvents()
|
||||||
{
|
{
|
||||||
LOGGER.info("Registering Fabric Server Events");
|
LOGGER.info("Registering Fabric Server Events");
|
||||||
@@ -75,19 +89,27 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
// ServerTickEvent
|
// ServerTickEvent
|
||||||
ServerTickEvents.END_SERVER_TICK.register((server) -> SERVER_API.serverTickEvent());
|
ServerTickEvents.END_SERVER_TICK.register((server) -> SERVER_API.serverTickEvent());
|
||||||
|
|
||||||
|
|
||||||
|
// can be enabled to test world gen overrides without having to build a separate API project
|
||||||
|
if (false)
|
||||||
|
{
|
||||||
|
DhApiEventRegister.on(DhApiLevelLoadEvent.class, new TestWorldGenBindingEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ServerWorldLoadEvent
|
// ServerWorldLoadEvent
|
||||||
//TODO: Check if both of these use the correct timed events. (i.e. is it 'ed' or 'ing' one?)
|
//TODO: Check if both of these use the correct timed events. (i.e. is it 'ed' or 'ing' one?)
|
||||||
ServerLifecycleEvents.SERVER_STARTING.register((server) ->
|
ServerLifecycleEvents.SERVER_STARTING.register((server) ->
|
||||||
{
|
{
|
||||||
if (isValidTime())
|
if (this.isValidTime())
|
||||||
{
|
{
|
||||||
ServerApi.INSTANCE.serverLoadEvent(isDedicated);
|
ServerApi.INSTANCE.serverLoadEvent(this.isDedicated);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// ServerWorldUnloadEvent
|
// ServerWorldUnloadEvent
|
||||||
ServerLifecycleEvents.SERVER_STOPPED.register((server) ->
|
ServerLifecycleEvents.SERVER_STOPPED.register((server) ->
|
||||||
{
|
{
|
||||||
if (isValidTime())
|
if (this.isValidTime())
|
||||||
{
|
{
|
||||||
ServerApi.INSTANCE.serverUnloadEvent();
|
ServerApi.INSTANCE.serverUnloadEvent();
|
||||||
}
|
}
|
||||||
@@ -96,25 +118,25 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
// ServerLevelLoadEvent
|
// ServerLevelLoadEvent
|
||||||
ServerWorldEvents.LOAD.register((server, level) ->
|
ServerWorldEvents.LOAD.register((server, level) ->
|
||||||
{
|
{
|
||||||
if (isValidTime())
|
if (this.isValidTime())
|
||||||
{
|
{
|
||||||
ServerApi.INSTANCE.serverLevelLoadEvent(getServerLevelWrapper(level));
|
ServerApi.INSTANCE.serverLevelLoadEvent(this.getServerLevelWrapper(level));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// ServerLevelUnloadEvent
|
// ServerLevelUnloadEvent
|
||||||
ServerWorldEvents.UNLOAD.register((server, level) ->
|
ServerWorldEvents.UNLOAD.register((server, level) ->
|
||||||
{
|
{
|
||||||
if (isValidTime())
|
if (this.isValidTime())
|
||||||
{
|
{
|
||||||
ServerApi.INSTANCE.serverLevelUnloadEvent(getServerLevelWrapper(level));
|
ServerApi.INSTANCE.serverLevelUnloadEvent(this.getServerLevelWrapper(level));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ServerChunkLoadEvent
|
// ServerChunkLoadEvent
|
||||||
ServerChunkEvents.CHUNK_LOAD.register((server, chunk) ->
|
ServerChunkEvents.CHUNK_LOAD.register((server, chunk) ->
|
||||||
{
|
{
|
||||||
ILevelWrapper level = getServerLevelWrapper((ServerLevel) chunk.getLevel());
|
ILevelWrapper level = this.getServerLevelWrapper((ServerLevel) chunk.getLevel());
|
||||||
if (isValidTime())
|
if (this.isValidTime())
|
||||||
{
|
{
|
||||||
ServerApi.INSTANCE.serverChunkLoadEvent(
|
ServerApi.INSTANCE.serverChunkLoadEvent(
|
||||||
new ChunkWrapper(chunk, chunk.getLevel(), level),
|
new ChunkWrapper(chunk, chunk.getLevel(), level),
|
||||||
@@ -125,18 +147,56 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
|
|
||||||
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) ->
|
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) ->
|
||||||
{
|
{
|
||||||
if (isValidTime())
|
if (this.isValidTime())
|
||||||
{
|
{
|
||||||
ServerApi.INSTANCE.serverPlayerJoinEvent(getServerPlayerWrapper(handler.player));
|
ServerApi.INSTANCE.serverPlayerJoinEvent(this.getServerPlayerWrapper(handler.player));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) ->
|
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) ->
|
||||||
{
|
{
|
||||||
if (isValidTime())
|
if (this.isValidTime())
|
||||||
{
|
{
|
||||||
ServerApi.INSTANCE.serverPlayerDisconnectEvent(getServerPlayerWrapper(handler.player));
|
ServerApi.INSTANCE.serverPlayerDisconnectEvent(this.getServerPlayerWrapper(handler.player));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ServerEntityWorldChangeEvents.AFTER_PLAYER_CHANGE_WORLD.register((player, origin, dest) ->
|
||||||
|
{
|
||||||
|
if (this.isValidTime())
|
||||||
|
{
|
||||||
|
ServerApi.INSTANCE.serverPlayerLevelChangeEvent(
|
||||||
|
this.getServerPlayerWrapper(player),
|
||||||
|
this.getServerLevelWrapper(origin),
|
||||||
|
this.getServerLevelWrapper(dest)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.isDedicated)
|
||||||
|
{
|
||||||
|
#if MC_VER >= MC_1_20_6
|
||||||
|
PayloadTypeRegistry.playC2S().register(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec());
|
||||||
|
PayloadTypeRegistry.playS2C().register(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec());
|
||||||
|
ServerPlayNetworking.registerGlobalReceiver(CommonPacketPayload.TYPE, (payload, context) ->
|
||||||
|
{
|
||||||
|
if (payload.message() == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ServerApi.INSTANCE.pluginMessageReceived(ServerPlayerWrapper.getWrapper(context.player()), payload.message());
|
||||||
|
});
|
||||||
|
#else
|
||||||
|
ServerPlayNetworking.registerGlobalReceiver(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE, (server, serverPlayer, handler, buffer, packetSender) ->
|
||||||
|
{
|
||||||
|
// Forge packet ID
|
||||||
|
buffer.readByte();
|
||||||
|
NetworkMessage message = AbstractPluginPacketSender.decodeMessage(buffer);
|
||||||
|
if (message != null)
|
||||||
|
{
|
||||||
|
ServerApi.INSTANCE.pluginMessageReceived(ServerPlayerWrapper.getWrapper(serverPlayer), message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
-28
@@ -21,33 +21,9 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
|||||||
@Mixin(ClientPacketListener.class)
|
@Mixin(ClientPacketListener.class)
|
||||||
public class MixinClientPacketListener
|
public class MixinClientPacketListener
|
||||||
{
|
{
|
||||||
@Shadow
|
|
||||||
private ClientLevel level;
|
|
||||||
|
|
||||||
@Unique
|
|
||||||
private ClientLevel previousLevel;
|
|
||||||
|
|
||||||
|
|
||||||
@Inject(method = "handleLogin", at = @At("RETURN"))
|
@Inject(method = "handleLogin", at = @At("RETURN"))
|
||||||
void onHandleLoginEnd(CallbackInfo ci) { ClientApi.INSTANCE.onClientOnlyConnected(); }
|
void onHandleLoginEnd(CallbackInfo ci) { ClientApi.INSTANCE.onClientOnlyConnected(); }
|
||||||
|
|
||||||
@Inject(method = "handleRespawn", at = @At("HEAD"))
|
|
||||||
void onHandleRespawnStart(CallbackInfo ci) { this.previousLevel = this.level; }
|
|
||||||
@Inject(method = "handleRespawn", at = @At("RETURN"))
|
|
||||||
void onHandleRespawnEnd(CallbackInfo ci)
|
|
||||||
{
|
|
||||||
// If the player changes dimensions the "this.level" will be changed halfway through the respawn method.
|
|
||||||
// By checking if the object references are the same, we can see if the previous level should be unloaded
|
|
||||||
// or if the player just respawned in the same level.
|
|
||||||
if (this.previousLevel != this.level)
|
|
||||||
{
|
|
||||||
ClientApi.INSTANCE.clientLevelUnloadEvent(ClientLevelWrapper.getWrapper(this.previousLevel));
|
|
||||||
ClientApi.INSTANCE.clientLevelLoadEvent(ClientLevelWrapper.getWrapper(this.level));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.previousLevel = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_4
|
#if MC_VER < MC_1_19_4
|
||||||
@Inject(method = "cleanup", at = @At("HEAD"))
|
@Inject(method = "cleanup", at = @At("HEAD"))
|
||||||
#else
|
#else
|
||||||
@@ -55,10 +31,6 @@ public class MixinClientPacketListener
|
|||||||
#endif
|
#endif
|
||||||
void onCleanupStart(CallbackInfo ci)
|
void onCleanupStart(CallbackInfo ci)
|
||||||
{
|
{
|
||||||
if (this.level != null)
|
|
||||||
{
|
|
||||||
ClientApi.INSTANCE.clientLevelUnloadEvent(ClientLevelWrapper.getWrapper(this.level));
|
|
||||||
}
|
|
||||||
ClientApi.INSTANCE.onClientOnlyDisconnected();
|
ClientApi.INSTANCE.onClientOnlyDisconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-11
@@ -22,6 +22,7 @@ package com.seibel.distanthorizons.fabric.mixins.client;
|
|||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
#if MC_VER < MC_1_19_4
|
#if MC_VER < MC_1_19_4
|
||||||
import com.mojang.math.Matrix4f;
|
import com.mojang.math.Matrix4f;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
#else
|
#else
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
#endif
|
#endif
|
||||||
@@ -29,23 +30,17 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
|||||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.GameRenderer;
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
import net.minecraft.client.Camera;
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.client.renderer.GameRenderer;
|
|
||||||
import net.minecraft.client.renderer.LevelRenderer;
|
import net.minecraft.client.renderer.LevelRenderer;
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
|
||||||
import org.lwjgl.opengl.GL15;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
@@ -99,7 +94,7 @@ public class MixinLevelRenderer
|
|||||||
#if MC_VER == MC_1_16_5
|
#if MC_VER == MC_1_16_5
|
||||||
// get the matrices from the OpenGL fixed pipeline
|
// get the matrices from the OpenGL fixed pipeline
|
||||||
float[] mcProjMatrixRaw = new float[16];
|
float[] mcProjMatrixRaw = new float[16];
|
||||||
GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
|
GL32.glGetFloatv(GL32.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
|
||||||
Mat4f mcProjectionMatrix = new Mat4f(mcProjMatrixRaw);
|
Mat4f mcProjectionMatrix = new Mat4f(mcProjMatrixRaw);
|
||||||
mcProjectionMatrix.transpose();
|
mcProjectionMatrix.transpose();
|
||||||
|
|
||||||
@@ -110,17 +105,23 @@ public class MixinLevelRenderer
|
|||||||
Mat4f mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose());
|
Mat4f mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose());
|
||||||
Mat4f mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
|
Mat4f mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
|
||||||
#else
|
#else
|
||||||
// get the matrices directly from MC
|
// MC combined the model view and projection matricies
|
||||||
Mat4f mcModelViewMatrix = McObjectConverter.Convert(projectionMatrix);
|
Mat4f mcModelViewMatrix = McObjectConverter.Convert(projectionMatrix);
|
||||||
Mat4f mcProjectionMatrix = new Mat4f();
|
Mat4f mcProjectionMatrix = new Mat4f();
|
||||||
mcProjectionMatrix.setIdentity();
|
mcProjectionMatrix.setIdentity();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (renderType.equals(RenderType.translucent())) {
|
if (renderType.equals(RenderType.translucent()))
|
||||||
|
{
|
||||||
ClientApi.INSTANCE.renderDeferredLods(ClientLevelWrapper.getWrapper(this.level),
|
ClientApi.INSTANCE.renderDeferredLods(ClientLevelWrapper.getWrapper(this.level),
|
||||||
mcModelViewMatrix,
|
mcModelViewMatrix,
|
||||||
mcProjectionMatrix,
|
mcProjectionMatrix,
|
||||||
Minecraft.getInstance().getFrameTime());
|
#if MC_VER < MC_1_21_1
|
||||||
|
Minecraft.getInstance().getFrameTime()
|
||||||
|
#else
|
||||||
|
Minecraft.getInstance().getTimer().getRealtimeDeltaTicks()
|
||||||
|
#endif
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME completely disables rendering when sodium is installed
|
// FIXME completely disables rendering when sodium is installed
|
||||||
|
|||||||
+40
-5
@@ -2,16 +2,21 @@ package com.seibel.distanthorizons.fabric.mixins.client;
|
|||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
|
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
|
||||||
import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
|
import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
|
import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
|
||||||
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
|
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
|
||||||
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
|
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.screens.TitleScreen;
|
import net.minecraft.client.gui.screens.TitleScreen;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
@@ -24,8 +29,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
* @author coolGi
|
* @author coolGi
|
||||||
*/
|
*/
|
||||||
@Mixin(Minecraft.class)
|
@Mixin(Minecraft.class)
|
||||||
public class MixinMinecraft
|
public abstract class MixinMinecraft
|
||||||
{
|
{
|
||||||
|
@Shadow
|
||||||
|
public abstract boolean isLocalServer();
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private ClientLevel lastLevel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can be enabled for testing the auto updater UI. <br/>
|
* Can be enabled for testing the auto updater UI. <br/>
|
||||||
* will always show the auto updater if set to true.
|
* will always show the auto updater if set to true.
|
||||||
@@ -87,13 +98,23 @@ public class MixinMinecraft
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
runnable = () -> {
|
runnable = () ->
|
||||||
|
{
|
||||||
|
String versionId;
|
||||||
|
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
|
||||||
|
if (updateBranch == EDhApiUpdateBranch.STABLE)
|
||||||
|
{
|
||||||
|
versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
versionId = GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha");
|
||||||
|
}
|
||||||
|
|
||||||
Minecraft.getInstance().setScreen(new UpdateModScreen(
|
Minecraft.getInstance().setScreen(new UpdateModScreen(
|
||||||
// TODO: Change to runnable, instead of tittle screen
|
// TODO: Change to runnable, instead of tittle screen
|
||||||
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
|
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
|
||||||
(Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE
|
versionId
|
||||||
? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion())
|
|
||||||
: GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
|
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -102,6 +123,20 @@ public class MixinMinecraft
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@Inject(at = @At("HEAD"), method = "updateLevelInEngines")
|
||||||
|
public void updateLevelInEngines(ClientLevel level, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
if (this.lastLevel != null && level != this.lastLevel)
|
||||||
|
{
|
||||||
|
ClientApi.INSTANCE.clientLevelUnloadEvent(ClientLevelWrapper.getWrapper(this.lastLevel));
|
||||||
|
}
|
||||||
|
if (level != null)
|
||||||
|
{
|
||||||
|
ClientApi.INSTANCE.clientLevelLoadEvent(ClientLevelWrapper.getWrapper(level, true));
|
||||||
|
}
|
||||||
|
this.lastLevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
@Inject(at = @At("HEAD"), method = "close()V")
|
@Inject(at = @At("HEAD"), method = "close()V")
|
||||||
public void close(CallbackInfo ci) { SelfUpdater.onClose(); }
|
public void close(CallbackInfo ci) { SelfUpdater.onClose(); }
|
||||||
|
|
||||||
|
|||||||
+17
-6
@@ -23,16 +23,13 @@ import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
|
|||||||
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
|
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
import net.minecraft.client.gui.screens.OptionsScreen;
|
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
import net.minecraft.network.chat.TranslatableComponent;
|
import net.minecraft.network.chat.TranslatableComponent;
|
||||||
#endif
|
#endif
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
@@ -41,11 +38,20 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
#if MC_VER == MC_1_20_6
|
#if MC_VER >= MC_1_20_6
|
||||||
import net.minecraft.client.gui.layouts.LinearLayout;
|
import net.minecraft.client.gui.layouts.LinearLayout;
|
||||||
import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
|
import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
import net.minecraft.client.gui.screens.OptionsScreen;
|
||||||
|
#else
|
||||||
|
import net.minecraft.client.gui.screens.options.OptionsScreen;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a button to the menu to goto the config
|
* Adds a button to the menu to goto the config
|
||||||
*
|
*
|
||||||
@@ -57,13 +63,18 @@ public class MixinOptionsScreen extends Screen
|
|||||||
{
|
{
|
||||||
/** Texture used for the config opening button */
|
/** Texture used for the config opening button */
|
||||||
@Unique
|
@Unique
|
||||||
private static final ResourceLocation ICON_TEXTURE = new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
|
private static final ResourceLocation ICON_TEXTURE =
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
|
||||||
|
#else
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private TexturedButtonWidget optionsButton = null;
|
private TexturedButtonWidget optionsButton = null;
|
||||||
|
|
||||||
#if MC_VER == MC_1_20_6
|
#if MC_VER >= MC_1_20_6
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
protected HeaderAndFooterLayout layout;
|
protected HeaderAndFooterLayout layout;
|
||||||
|
|||||||
+2
-60
@@ -1,8 +1,6 @@
|
|||||||
package com.seibel.distanthorizons.fabric.mixins.server;
|
package com.seibel.distanthorizons.fabric.mixins.server;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.commonMixins.MixinChunkMapCommon;
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
@@ -32,62 +30,6 @@ public class MixinChunkMap
|
|||||||
// don't need the chunk(s) before MC has finished saving them
|
// don't need the chunk(s) before MC has finished saving them
|
||||||
@Inject(method = "save", at = @At(value = "RETURN", target = CHUNK_SERIALIZER_WRITE))
|
@Inject(method = "save", at = @At(value = "RETURN", target = CHUNK_SERIALIZER_WRITE))
|
||||||
private void onChunkSave(ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
|
private void onChunkSave(ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
|
||||||
{
|
{ MixinChunkMapCommon.onChunkSave(this.level, chunk, ci); }
|
||||||
// true means a chunk was saved to disk
|
|
||||||
if (ci.getReturnValue())
|
|
||||||
{
|
|
||||||
// TODO is this validation necessary since we are checking above if
|
|
||||||
// the callback return value should state if the chunk was actually saved or not?
|
|
||||||
// Do we trust it to always be correct?
|
|
||||||
|
|
||||||
//=====================================//
|
|
||||||
// corrupt/incomplete chunk validation //
|
|
||||||
//=====================================//
|
|
||||||
|
|
||||||
// MC has a tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks)
|
|
||||||
// this logic should prevent that from happening
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
|
||||||
if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//==================//
|
|
||||||
// biome validation //
|
|
||||||
//==================//
|
|
||||||
|
|
||||||
// some chunks may be missing their biomes, which cause issues when attempting to save them
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
|
||||||
if (chunk.getBiomes() == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// this will throw an exception if the biomes aren't set up
|
|
||||||
chunk.getNoiseBiome(0,0,0);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ServerApi.INSTANCE.serverChunkSaveEvent(
|
|
||||||
new ChunkWrapper(chunk, this.level, ServerLevelWrapper.getWrapper(this.level)),
|
|
||||||
ServerLevelWrapper.getWrapper(this.level)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020-2023 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.fabric.mixins.server;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.IMixinServerPlayer;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_21_1
|
||||||
|
import net.minecraft.world.level.portal.DimensionTransition;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@Mixin(ServerPlayer.class)
|
||||||
|
public class MixinServerPlayer implements IMixinServerPlayer
|
||||||
|
{
|
||||||
|
@Unique
|
||||||
|
@Nullable
|
||||||
|
private ServerLevel dimensionChangeDestination;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public ServerLevel distantHorizons$getDimensionChangeDestination()
|
||||||
|
{
|
||||||
|
return this.dimensionChangeDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At("HEAD"), method = "changeDimension")
|
||||||
|
#if MC_VER >= MC_1_21_1
|
||||||
|
public void changeDimension(DimensionTransition dimensionTransition, CallbackInfoReturnable<Entity> cir)
|
||||||
|
{
|
||||||
|
this.dimensionChangeDestination = dimensionTransition.newLevel();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
public void changeDimension(ServerLevel destination, CallbackInfoReturnable<Entity> cir)
|
||||||
|
{
|
||||||
|
this.dimensionChangeDestination = destination;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_20_1
|
||||||
|
@Inject(at = @At("RETURN"), method = "setServerLevel")
|
||||||
|
public void setServerLevel(ServerLevel level, CallbackInfo ci)
|
||||||
|
#else
|
||||||
|
@Inject(at = @At("RETURN"), method = "setLevel")
|
||||||
|
public void setLevel(ServerLevel level, CallbackInfo ci)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
this.dimensionChangeDestination = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
package com.seibel.distanthorizons.fabric.testing;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.DhApi;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGenerator;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
public class TestWorldGenBindingEvent extends DhApiLevelLoadEvent
|
||||||
|
{
|
||||||
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLevelLoad(DhApiEventParam<DhApiLevelLoadEvent.EventParam> event)
|
||||||
|
{
|
||||||
|
LOGGER.info("DH Level: ["+event.value.levelWrapper.getDimensionType()+"] loaded.");
|
||||||
|
|
||||||
|
// Note: whenever you use a wrapper method on a new Minecraft version it is recommended that you
|
||||||
|
// call wrapper.getClass() to determine which object the API will return before you try casting it.
|
||||||
|
ServerLevel level = (ServerLevel) event.value.levelWrapper.getWrappedMcObject();
|
||||||
|
|
||||||
|
// override the core DH world generator for this level
|
||||||
|
IDhApiWorldGenerator exampleWorldGen = new TestWorldGenerator(level);
|
||||||
|
DhApi.worldGenOverrides.registerWorldGeneratorOverride(event.value.levelWrapper, exampleWorldGen);
|
||||||
|
}
|
||||||
|
}
|
||||||
+114
@@ -0,0 +1,114 @@
|
|||||||
|
package com.seibel.distanthorizons.fabric.testing;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.DhApi;
|
||||||
|
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
||||||
|
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGeneratorReturnType;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.AbstractDhApiChunkWorldGenerator;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
|
||||||
|
import com.seibel.distanthorizons.api.objects.data.DhApiChunk;
|
||||||
|
import com.seibel.distanthorizons.api.objects.data.DhApiTerrainDataPoint;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class TestWorldGenerator extends AbstractDhApiChunkWorldGenerator
|
||||||
|
{
|
||||||
|
private final ServerLevel level;
|
||||||
|
private final IDhApiLevelWrapper levelWrapper;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
public TestWorldGenerator(ServerLevel level)
|
||||||
|
{
|
||||||
|
this.level = level;
|
||||||
|
this.levelWrapper = ServerLevelWrapper.getWrapper(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// properties //
|
||||||
|
//============//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EDhApiWorldGeneratorReturnType getReturnType() { return EDhApiWorldGeneratorReturnType.API_CHUNKS; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean runApiChunkValidation() { return true; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==================//
|
||||||
|
// chunk generation //
|
||||||
|
//==================//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] generateChunk(int chunkX, int chunkZ, EDhApiDistantGeneratorMode eDhApiDistantGeneratorMode)
|
||||||
|
{
|
||||||
|
ChunkAccess chunk = this.level.getChunk(chunkX, chunkZ);
|
||||||
|
return new Object[] { chunk, this.level };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DhApiChunk generateApiChunk(int chunkPosX, int chunkPosZ, EDhApiDistantGeneratorMode generatorMode)
|
||||||
|
{
|
||||||
|
// this test is only validated for 1.18.2 and up
|
||||||
|
// (and it is only needed when testing world gen overrides/API chunks, so it isn't normally needed)
|
||||||
|
#if MC_VER >= MC_1_18_2
|
||||||
|
ChunkAccess chunk = this.level.getChunk(chunkPosX, chunkPosZ);
|
||||||
|
|
||||||
|
|
||||||
|
int minBuildHeight = this.level.getMinBuildHeight();
|
||||||
|
int maxBuildHeight = this.level.getMaxBuildHeight();
|
||||||
|
|
||||||
|
DhApiChunk apiChunk = DhApiChunk.create(chunkPosX, chunkPosZ, minBuildHeight, maxBuildHeight);
|
||||||
|
for (int x = 0; x < 16; x++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < 16; z++)
|
||||||
|
{
|
||||||
|
ArrayList<DhApiTerrainDataPoint> dataPoints = new ArrayList<>();
|
||||||
|
|
||||||
|
IDhApiBlockStateWrapper block = null;
|
||||||
|
IDhApiBiomeWrapper biome = null;
|
||||||
|
|
||||||
|
for (int y = minBuildHeight; y < maxBuildHeight; y++)
|
||||||
|
{
|
||||||
|
block = DhApi.Delayed.wrapperFactory.getBlockStateWrapper(new Object[]{chunk.getBlockState(new BlockPos(x, y, z))}, this.levelWrapper);
|
||||||
|
biome = DhApi.Delayed.wrapperFactory.getBiomeWrapper(new Object[]{chunk.getNoiseBiome(x, y, z)}, this.levelWrapper);
|
||||||
|
dataPoints.add(DhApiTerrainDataPoint.create((byte) 0, 0, 15, y, y + 1, block, biome));
|
||||||
|
}
|
||||||
|
|
||||||
|
apiChunk.setDataPoints(x, z, dataPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return apiChunk;
|
||||||
|
#else
|
||||||
|
return null;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preGeneratorTaskStart() { /* do nothing */ }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// cleanup //
|
||||||
|
//=========//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() { /* do nothing */ }
|
||||||
|
|
||||||
|
}
|
||||||
+3
-2
@@ -5,7 +5,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IBCLibAcces
|
|||||||
#elif MC_VER == MC_1_18_2
|
#elif MC_VER == MC_1_18_2
|
||||||
import ru.bclib.config.ClientConfig;
|
import ru.bclib.config.ClientConfig;
|
||||||
import ru.bclib.config.Configs;
|
import ru.bclib.config.Configs;
|
||||||
#else
|
#elif MC_VER < MC_1_21_1
|
||||||
import org.betterx.bclib.config.ClientConfig;
|
import org.betterx.bclib.config.ClientConfig;
|
||||||
import org.betterx.bclib.config.Configs;
|
import org.betterx.bclib.config.Configs;
|
||||||
#endif
|
#endif
|
||||||
@@ -17,7 +17,8 @@ public class BCLibAccessor implements IBCLibAccessor
|
|||||||
|
|
||||||
public void setRenderCustomFog(boolean newValue)
|
public void setRenderCustomFog(boolean newValue)
|
||||||
{
|
{
|
||||||
#if !(MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 || MC_VER == MC_1_20_4 || MC_VER == MC_1_20_6) // These versions either don't have BCLib, or the implementation is different
|
// only some MC versions have BCLib and require this fix
|
||||||
|
#if (MC_VER > MC_1_17_1 && MC_VER < MC_1_20_4)
|
||||||
|
|
||||||
// Change the value of CUSTOM_FOG_RENDERING in the bclib client config
|
// Change the value of CUSTOM_FOG_RENDERING in the bclib client config
|
||||||
// This disabled fog from rendering within bclib
|
// This disabled fog from rendering within bclib
|
||||||
|
|||||||
+88
-93
@@ -19,20 +19,18 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.fabric.wrappers.modAccessor;
|
package com.seibel.distanthorizons.fabric.wrappers.modAccessor;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.util.stream.Collectors;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
||||||
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
#if MC_VER < MC_1_20_1
|
||||||
import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer;
|
import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer;
|
||||||
import net.minecraft.client.Minecraft;
|
#endif
|
||||||
#if MC_VER < MC_1_17_1
|
#if MC_VER < MC_1_17_1
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.protocol.Packet;
|
import net.minecraft.network.protocol.Packet;
|
||||||
@@ -41,102 +39,99 @@ import net.minecraft.world.entity.EntityType;
|
|||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
#else
|
#else
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public class SodiumAccessor implements ISodiumAccessor
|
public class SodiumAccessor implements ISodiumAccessor
|
||||||
{
|
{
|
||||||
private final IWrapperFactory factory = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
|
#if MC_VER >= MC_1_20_1
|
||||||
private final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
private static MethodHandle setFogOcclusionMethod;
|
||||||
|
private static Object sodiumPerformanceOptions;
|
||||||
public IClientLevelWrapper levelWrapper;
|
|
||||||
public Mat4f mcModelViewMatrix;
|
|
||||||
public Mat4f mcProjectionMatrix;
|
|
||||||
public float partialTicks;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getModName()
|
|
||||||
{
|
|
||||||
return "Sodium-Fabric";
|
|
||||||
}
|
|
||||||
|
|
||||||
#if MC_VER >= MC_1_17_1
|
|
||||||
@Override
|
|
||||||
public HashSet<DhChunkPos> getNormalRenderedChunks()
|
|
||||||
{
|
|
||||||
SodiumWorldRenderer renderer = SodiumWorldRenderer.instance();
|
|
||||||
LevelHeightAccessor height = Minecraft.getInstance().level;
|
|
||||||
|
|
||||||
#if MC_VER >= MC_1_20_1
|
|
||||||
// TODO: This is just a tmp solution, use a proper solution later
|
|
||||||
return MC_RENDER.getMaximumRenderedChunks().stream().filter((DhChunkPos chunk) -> {
|
|
||||||
return (renderer.isBoxVisible(
|
|
||||||
chunk.getMinBlockX() + 1, height.getMinBuildHeight() + 1, chunk.getMinBlockZ() + 1,
|
|
||||||
chunk.getMinBlockX() + 15, height.getMaxBuildHeight() - 1, chunk.getMinBlockZ() + 15));
|
|
||||||
}).collect(Collectors.toCollection(HashSet::new));
|
|
||||||
#elif MC_VER >= MC_1_18_2
|
|
||||||
// 0b11 = Lighted chunk & loaded chunk
|
|
||||||
return renderer.getChunkTracker().getChunks(0b00).filter(
|
|
||||||
(long l) -> {
|
|
||||||
return true;
|
|
||||||
}).mapToObj(DhChunkPos::new).collect(Collectors.toCollection(HashSet::new));
|
|
||||||
#else
|
|
||||||
// TODO: Maybe use a mixin to make this more efficient, and maybe ignore changes behind the camera
|
|
||||||
return MC_RENDER.getMaximumRenderedChunks().stream().filter((DhChunkPos chunk) -> {
|
|
||||||
return (renderer.isBoxVisible(
|
|
||||||
chunk.getMinBlockX() + 1, height.getMinBuildHeight() + 1, chunk.getMinBlockZ() + 1,
|
|
||||||
chunk.getMinBlockX() + 15, height.getMaxBuildHeight() - 1, chunk.getMinBlockZ() + 15));
|
|
||||||
}).collect(Collectors.toCollection(HashSet::new));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
@Override
|
|
||||||
public HashSet<DhChunkPos> getNormalRenderedChunks() {
|
|
||||||
SodiumWorldRenderer renderer = SodiumWorldRenderer.getInstance();
|
|
||||||
LevelAccessor height = Minecraft.getInstance().level;
|
|
||||||
// TODO: Maybe use a mixin to make this more efficient
|
|
||||||
return MC_RENDER.getMaximumRenderedChunks().stream().filter((DhChunkPos chunk) -> {
|
|
||||||
FakeChunkEntity AABB = new FakeChunkEntity(chunk.x, chunk.z, height.getMaxBuildHeight());
|
|
||||||
return (renderer.isEntityVisible(AABB));
|
|
||||||
}).collect(Collectors.toCollection(HashSet::new));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class FakeChunkEntity extends Entity {
|
|
||||||
public int cx;
|
|
||||||
public int cz;
|
|
||||||
public int my;
|
|
||||||
public FakeChunkEntity(int chunkX, int chunkZ, int maxHeight) {
|
|
||||||
super(EntityType.AREA_EFFECT_CLOUD, null);
|
|
||||||
cx = chunkX;
|
|
||||||
cz = chunkZ;
|
|
||||||
my = maxHeight;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public AABB getBoundingBoxForCulling() {
|
|
||||||
return new AABB(cx*16+1, 1, cz*16+1,
|
|
||||||
cx*16+15, my-1, cz*16+15);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
protected void defineSynchedData() {}
|
|
||||||
@Override
|
|
||||||
protected void readAdditionalSaveData(CompoundTag paramCompoundTag) {}
|
|
||||||
@Override
|
|
||||||
protected void addAdditionalSaveData(CompoundTag paramCompoundTag) {}
|
|
||||||
@Override
|
|
||||||
public Packet<?> getAddEntityPacket() {
|
|
||||||
throw new UnsupportedOperationException("This is a FAKE CHUNK ENTITY... For tricking the Sodium to check a AABB.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** A temporary overwrite for a config in sodium 0.5 to fix their terrain from showing, will be removed once a proper fix is added */
|
|
||||||
// FIXME
|
|
||||||
|
//======================//
|
||||||
|
// mod accessor methods //
|
||||||
|
//======================//
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFogOcclusion(boolean b)
|
public String getModName() { return "Sodium-Fabric"; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// sodium methods //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
/** An overwrite for a config in sodium 0.5 to fix their terrain from showing */
|
||||||
|
@Override
|
||||||
|
public void setFogOcclusion(boolean occlusionEnabled)
|
||||||
{
|
{
|
||||||
#if MC_VER >= MC_1_20_1
|
#if MC_VER >= MC_1_20_1
|
||||||
me.jellysquid.mods.sodium.client.SodiumClientMod.options().performance.useFogOcclusion = b;
|
try
|
||||||
|
{
|
||||||
|
if (sodiumPerformanceOptions == null)
|
||||||
|
{
|
||||||
|
boolean sodiumV6 = classPresent("net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer");
|
||||||
|
if (!sodiumV6)
|
||||||
|
{
|
||||||
|
// sodium 0.5
|
||||||
|
|
||||||
|
Class<?> optionsClass = Class.forName("me.jellysquid.mods.sodium.client.gui.SodiumGameOptions");
|
||||||
|
Object basicOptions = MethodHandles.lookup().findStatic(
|
||||||
|
Class.forName("me.jellysquid.mods.sodium.client.SodiumClientMod"),
|
||||||
|
"options", MethodType.methodType(optionsClass)).invoke();
|
||||||
|
sodiumPerformanceOptions = optionsClass.getDeclaredField("performance").get(basicOptions);
|
||||||
|
setFogOcclusionMethod = MethodHandles.lookup()
|
||||||
|
.findSetter(Class.forName(
|
||||||
|
"me.jellysquid.mods.sodium.client.gui.SodiumGameOptions$PerformanceSettings"),
|
||||||
|
"useFogOcclusion", boolean.class);
|
||||||
|
|
||||||
|
// alternate option if referencing Sodium 0.5 directly
|
||||||
|
//me.jellysquid.mods.sodium.client.SodiumClientMod.options().performance.useFogOcclusion = b;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// sodium 0.6
|
||||||
|
|
||||||
|
Class<?> optionsClass = Class.forName("net.caffeinemc.mods.sodium.client.gui.SodiumGameOptions");
|
||||||
|
Object basicOptions = MethodHandles.lookup().findStatic(
|
||||||
|
Class.forName("net.caffeinemc.mods.sodium.client.SodiumClientMod"),
|
||||||
|
"options", MethodType.methodType(optionsClass)).invoke();
|
||||||
|
sodiumPerformanceOptions = optionsClass.getDeclaredField("performance").get(basicOptions);
|
||||||
|
setFogOcclusionMethod = MethodHandles.lookup()
|
||||||
|
.findSetter(Class.forName(
|
||||||
|
"net.caffeinemc.mods.sodium.client.gui.SodiumGameOptions$PerformanceSettings"),
|
||||||
|
"useFogOcclusion", boolean.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setFogOcclusionMethod.invoke(sodiumPerformanceOptions, occlusionEnabled);
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper methods //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
private static boolean classPresent(String className)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Class.forName(className);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
"mixins": [
|
"mixins": [
|
||||||
"server.MixinChunkGenerator",
|
"server.MixinChunkGenerator",
|
||||||
"server.MixinChunkMap",
|
"server.MixinChunkMap",
|
||||||
"server.MixinUtilBackgroundThread"
|
"server.MixinUtilBackgroundThread",
|
||||||
|
"server.MixinServerPlayer"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinClientLevel",
|
"client.MixinClientLevel",
|
||||||
|
|||||||
@@ -56,7 +56,6 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"suggests": {
|
"suggests": {
|
||||||
"blendium": "*"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"breaks": $fabric_incompatibility_list,
|
"breaks": $fabric_incompatibility_list,
|
||||||
|
|||||||
+7
-5
@@ -37,15 +37,17 @@ loom {
|
|||||||
client {
|
client {
|
||||||
client()
|
client()
|
||||||
setConfigName("Forge Client")
|
setConfigName("Forge Client")
|
||||||
ideConfigGenerated(true)
|
ideConfigGenerated(false)
|
||||||
runDir("../run")
|
runDir("../run/client")
|
||||||
// vmArgs("-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg)
|
vmArgs("-Dio.netty.leakDetection.level=advanced")
|
||||||
|
programArgs("--username", "Dev")
|
||||||
}
|
}
|
||||||
server {
|
server {
|
||||||
server()
|
server()
|
||||||
setConfigName("Forge Server")
|
setConfigName("Forge Server")
|
||||||
ideConfigGenerated(true)
|
ideConfigGenerated(false)
|
||||||
runDir("../run")
|
runDir("../run/server")
|
||||||
|
vmArgs("-Dio.netty.leakDetection.level=advanced")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,13 +27,12 @@ import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
|||||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
|
||||||
//import io.netty.buffer.ByteBuf;
|
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
@@ -52,8 +51,6 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
|||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
//import net.minecraftforge.network.NetworkRegistry;
|
|
||||||
//import net.minecraftforge.network.simple.SimpleChannel;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
@@ -65,6 +62,8 @@ import net.minecraftforge.event.TickEvent;
|
|||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import org.lwjgl.opengl.GL32;
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This handles all events sent to the client,
|
* This handles all events sent to the client,
|
||||||
* and is the starting point for most of the mod.
|
* and is the starting point for most of the mod.
|
||||||
@@ -77,8 +76,6 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||||
|
|
||||||
// private static SimpleChannel multiversePluginChannel;
|
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
private static LevelAccessor GetEventLevel(WorldEvent e) { return e.getWorld(); }
|
private static LevelAccessor GetEventLevel(WorldEvent e) { return e.getWorld(); }
|
||||||
@@ -92,7 +89,7 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
public void registerEvents()
|
public void registerEvents()
|
||||||
{
|
{
|
||||||
MinecraftForge.EVENT_BUS.register(this);
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
this.setupNetworkingListeners();
|
ForgePluginPacketSender.setPacketHandler(ClientApi.INSTANCE::pluginMessageReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -136,7 +133,7 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClientLevel clientLevel = (ClientLevel) level;
|
ClientLevel clientLevel = (ClientLevel) level;
|
||||||
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel);
|
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel, true);
|
||||||
// TODO this causes a crash due to level being set to null somewhere
|
// TODO this causes a crash due to level being set to null somewhere
|
||||||
ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper);
|
ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper);
|
||||||
}
|
}
|
||||||
@@ -144,7 +141,7 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
public void clientLevelUnloadEvent(WorldEvent.Unload event)
|
public void clientLevelUnloadEvent(WorldEvent.Unload event)
|
||||||
#else
|
#else
|
||||||
public void clientLevelUnloadEvent(LevelEvent.Load event)
|
public void clientLevelUnloadEvent(LevelEvent.Unload event)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
LOGGER.info("level unload");
|
LOGGER.info("level unload");
|
||||||
@@ -173,40 +170,60 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void rightClickBlockEvent(PlayerInteractEvent.RightClickBlock event)
|
public void rightClickBlockEvent(PlayerInteractEvent.RightClickBlock event)
|
||||||
{
|
{
|
||||||
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
|
if (MC.clientConnectedToDedicatedServer())
|
||||||
{
|
{
|
||||||
return;
|
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//LOGGER.trace("interact or block place event at blockPos: " + event.getPos());
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_19_2
|
||||||
|
LevelAccessor level = event.getWorld();
|
||||||
|
#else
|
||||||
|
LevelAccessor level = event.getLevel();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
|
||||||
|
if (executor != null)
|
||||||
|
{
|
||||||
|
executor.execute(() ->
|
||||||
|
{
|
||||||
|
ChunkAccess chunk = level.getChunk(event.getPos());
|
||||||
|
this.onBlockChangeEvent(level, chunk);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//LOGGER.trace("interact or block place event at blockPos: " + event.getPos());
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_2
|
|
||||||
LevelAccessor level = event.getWorld();
|
|
||||||
#else
|
|
||||||
LevelAccessor level = event.getLevel();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ChunkAccess chunk = level.getChunk(event.getPos());
|
|
||||||
this.onBlockChangeEvent(level, chunk);
|
|
||||||
}
|
}
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void leftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event)
|
public void leftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event)
|
||||||
{
|
{
|
||||||
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
|
if (MC.clientConnectedToDedicatedServer())
|
||||||
{
|
{
|
||||||
return;
|
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//LOGGER.trace("break or block attack at blockPos: " + event.getPos());
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_19_2
|
||||||
|
LevelAccessor level = event.getWorld();
|
||||||
|
#else
|
||||||
|
LevelAccessor level = event.getLevel();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
|
||||||
|
if (executor != null)
|
||||||
|
{
|
||||||
|
executor.execute(() ->
|
||||||
|
{
|
||||||
|
ChunkAccess chunk = level.getChunk(event.getPos());
|
||||||
|
this.onBlockChangeEvent(level, chunk);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//LOGGER.trace("break or block attack at blockPos: " + event.getPos());
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_2
|
|
||||||
LevelAccessor level = event.getWorld();
|
|
||||||
#else
|
|
||||||
LevelAccessor level = event.getLevel();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ChunkAccess chunk = level.getChunk(event.getPos());
|
|
||||||
this.onBlockChangeEvent(level, chunk);
|
|
||||||
}
|
}
|
||||||
private void onBlockChangeEvent(LevelAccessor level, ChunkAccess chunk)
|
private void onBlockChangeEvent(LevelAccessor level, ChunkAccess chunk)
|
||||||
{
|
{
|
||||||
@@ -214,20 +231,15 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
SharedApi.INSTANCE.chunkBlockChangedEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
|
SharedApi.INSTANCE.chunkBlockChangedEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void clientChunkLoadEvent(ChunkEvent.Load event)
|
public void clientChunkLoadEvent(ChunkEvent.Load event)
|
||||||
{
|
{
|
||||||
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
|
if (MC.clientConnectedToDedicatedServer())
|
||||||
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), wrappedLevel);
|
{
|
||||||
SharedApi.INSTANCE.chunkLoadEvent(chunk, wrappedLevel);
|
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
|
||||||
}
|
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), wrappedLevel);
|
||||||
@SubscribeEvent
|
SharedApi.INSTANCE.chunkLoadEvent(chunk, wrappedLevel);
|
||||||
public void clientChunkUnloadEvent(ChunkEvent.Unload event)
|
}
|
||||||
{
|
|
||||||
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
|
|
||||||
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), wrappedLevel);
|
|
||||||
SharedApi.INSTANCE.chunkUnloadEvent(chunk, wrappedLevel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -252,66 +264,6 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============//
|
|
||||||
// networking //
|
|
||||||
//============//
|
|
||||||
|
|
||||||
public void setupNetworkingListeners()
|
|
||||||
{
|
|
||||||
// multiversePluginChannel = NetworkRegistry.newSimpleChannel(
|
|
||||||
// new ResourceLocation(ModInfo.NETWORKING_RESOURCE_NAMESPACE, ModInfo.MULTIVERSE_PLUGIN_NAMESPACE),
|
|
||||||
// // network protocol version
|
|
||||||
// () -> ModInfo.MULTIVERSE_PLUGIN_PROTOCOL_VERSION +"",
|
|
||||||
// // client accepted versions
|
|
||||||
// ForgeClientProxy::isReceivedProtocolVersionAcceptable,
|
|
||||||
// // server accepted versions
|
|
||||||
// ForgeClientProxy::isReceivedProtocolVersionAcceptable
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// multiversePluginChannel.registerMessage(0/*should be incremented for each simple channel we listen to*/, ByteBuf.class,
|
|
||||||
// // encoder
|
|
||||||
// (pack, friendlyByteBuf) -> { },
|
|
||||||
// // decoder
|
|
||||||
// (friendlyByteBuf) -> friendlyByteBuf.asByteBuf(),
|
|
||||||
// // message consumer
|
|
||||||
// (nettyByteBuf, contextRef) ->
|
|
||||||
// {
|
|
||||||
// ClientApi.INSTANCE.serverMessageReceived(nettyByteBuf);
|
|
||||||
// contextRef.get().setPacketHandled(true);
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isReceivedProtocolVersionAcceptable(String versionString)
|
|
||||||
{
|
|
||||||
if (versionString.toLowerCase().contains("allowvanilla"))
|
|
||||||
{
|
|
||||||
// allow using networking on vanilla servers
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (versionString.toLowerCase().contains("absent"))
|
|
||||||
{
|
|
||||||
// allow using networking even if DH isn't installed on the server
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// DH is installed on the server, check if the version is valid to use
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int version = Integer.parseInt(versionString);
|
|
||||||
return ModInfo.MULTIVERSE_PLUGIN_PROTOCOL_VERSION == version;
|
|
||||||
}
|
|
||||||
catch (NumberFormatException ignored)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===========//
|
//===========//
|
||||||
// rendering //
|
// rendering //
|
||||||
//===========//
|
//===========//
|
||||||
@@ -345,5 +297,4 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,11 @@ package com.seibel.distanthorizons.forge;
|
|||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
||||||
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
|
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||||
@@ -34,15 +38,16 @@ import net.minecraft.commands.CommandSourceStack;
|
|||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.EventPriority;
|
||||||
import net.minecraftforge.fml.ModLoadingContext;
|
import net.minecraftforge.fml.ModLoadingContext;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.event.lifecycle.*;
|
import net.minecraftforge.fml.event.lifecycle.*;
|
||||||
#if MC_VER == MC_1_16_5
|
#if MC_VER == MC_1_16_5
|
||||||
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
|
import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent;
|
||||||
#elif MC_VER == MC_1_17_1
|
#elif MC_VER == MC_1_17_1
|
||||||
import net.minecraftforge.fmlserverevents.FMLServerStartingEvent;
|
import net.minecraftforge.fmlserverevents.FMLServerAboutToStartEvent;
|
||||||
#else
|
#else
|
||||||
import net.minecraftforge.event.server.ServerStartingEvent;
|
import net.minecraftforge.event.server.ServerAboutToStartEvent;
|
||||||
#endif
|
#endif
|
||||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||||
#if MC_VER < MC_1_17_1
|
#if MC_VER < MC_1_17_1
|
||||||
@@ -81,7 +86,11 @@ public class ForgeMain extends AbstractModInitializer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createInitialBindings() { SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); }
|
protected void createInitialBindings()
|
||||||
|
{
|
||||||
|
SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
|
||||||
|
SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new ForgePluginPacketSender());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IEventProxy createClientProxy() { return new ForgeClientProxy(); }
|
protected IEventProxy createClientProxy() { return new ForgeClientProxy(); }
|
||||||
@@ -104,6 +113,20 @@ public class ForgeMain extends AbstractModInitializer
|
|||||||
ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class,
|
ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class,
|
||||||
() -> new ConfigScreenHandler.ConfigScreenFactory((client, parent) -> GetConfigScreen.getScreen(parent)));
|
() -> new ConfigScreenHandler.ConfigScreenFactory((client, parent) -> GetConfigScreen.getScreen(parent)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
if (Config.Client.Advanced.Logging.showModCompatibilityWarningsOnStartup.get())
|
||||||
|
{
|
||||||
|
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
|
||||||
|
if (modChecker.isModLoaded("alexscaves"))
|
||||||
|
{
|
||||||
|
String message =
|
||||||
|
// orange text
|
||||||
|
"\u00A76" + "Distant Horizons: Alex's Cave detected." + "\u00A7r\n" +
|
||||||
|
"You may have to change Alex's config for DH to render. ";
|
||||||
|
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -121,7 +144,7 @@ public class ForgeMain extends AbstractModInitializer
|
|||||||
@Override
|
@Override
|
||||||
protected void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler)
|
protected void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler)
|
||||||
{
|
{
|
||||||
MinecraftForge.EVENT_BUS.addListener((#if MC_VER >= MC_1_18_2 ServerStartingEvent #else FMLServerStartingEvent #endif e) ->
|
MinecraftForge.EVENT_BUS.addListener(EventPriority.HIGH, (#if MC_VER >= MC_1_18_2 ServerAboutToStartEvent #else FMLServerAboutToStartEvent #endif e) ->
|
||||||
{
|
{
|
||||||
eventHandler.accept(e.getServer());
|
eventHandler.accept(e.getServer());
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
package com.seibel.distanthorizons.forge;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_20_2
|
||||||
|
import net.minecraftforge.network.PacketDistributor;
|
||||||
|
import net.minecraftforge.network.ChannelBuilder;
|
||||||
|
import net.minecraftforge.network.SimpleChannel;
|
||||||
|
#elif MC_VER >= MC_1_18_2
|
||||||
|
import net.minecraftforge.network.PacketDistributor;
|
||||||
|
import net.minecraftforge.network.NetworkRegistry;
|
||||||
|
import net.minecraftforge.network.simple.SimpleChannel;
|
||||||
|
#elif MC_VER >= MC_1_17_1
|
||||||
|
import net.minecraftforge.fmllegacy.network.NetworkRegistry;
|
||||||
|
import net.minecraftforge.fmllegacy.network.PacketDistributor;
|
||||||
|
import net.minecraftforge.fmllegacy.network.simple.SimpleChannel;
|
||||||
|
#else // < 1.17.1
|
||||||
|
import net.minecraftforge.fml.network.NetworkRegistry;
|
||||||
|
import net.minecraftforge.fml.network.simple.SimpleChannel;
|
||||||
|
import net.minecraftforge.fml.network.PacketDistributor;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class ForgePluginPacketSender extends AbstractPluginPacketSender
|
||||||
|
{
|
||||||
|
public static final SimpleChannel PLUGIN_CHANNEL =
|
||||||
|
#if MC_VER >= MC_1_20_2
|
||||||
|
ChannelBuilder.named(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE)
|
||||||
|
.networkProtocolVersion(1)
|
||||||
|
.serverAcceptedVersions((status, version) -> true)
|
||||||
|
.clientAcceptedVersions((status, version) -> true)
|
||||||
|
.simpleChannel();
|
||||||
|
#else // < 1.20.2
|
||||||
|
NetworkRegistry.newSimpleChannel(
|
||||||
|
AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE,
|
||||||
|
() -> "1",
|
||||||
|
ignored -> true,
|
||||||
|
ignored -> true
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public static void setPacketHandler(Consumer<NetworkMessage> consumer)
|
||||||
|
{
|
||||||
|
setPacketHandler((player, message) -> consumer.accept(message));
|
||||||
|
}
|
||||||
|
public static void setPacketHandler(BiConsumer<IServerPlayerWrapper, NetworkMessage> consumer)
|
||||||
|
{
|
||||||
|
#if MC_VER >= MC_1_20_2
|
||||||
|
PLUGIN_CHANNEL.messageBuilder(MessageWrapper.class, 0)
|
||||||
|
.encoder((wrapper, out) -> AbstractPluginPacketSender.encodeMessage(out, wrapper.message))
|
||||||
|
.decoder(in -> new MessageWrapper(AbstractPluginPacketSender.decodeMessage(in)))
|
||||||
|
.consumerNetworkThread((wrapper, context) ->
|
||||||
|
{
|
||||||
|
if (wrapper.message != null)
|
||||||
|
{
|
||||||
|
if (context.getSender() != null)
|
||||||
|
{
|
||||||
|
consumer.accept(ServerPlayerWrapper.getWrapper(context.getSender()), wrapper.message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
consumer.accept(null, wrapper.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.setPacketHandled(true);
|
||||||
|
})
|
||||||
|
.add();
|
||||||
|
#else // < 1.20.2
|
||||||
|
PLUGIN_CHANNEL.registerMessage(0, MessageWrapper.class,
|
||||||
|
(wrapper, out) -> AbstractPluginPacketSender.encodeMessage(out, wrapper.message),
|
||||||
|
in -> new MessageWrapper(AbstractPluginPacketSender.decodeMessage(in)),
|
||||||
|
(wrapper, context) ->
|
||||||
|
{
|
||||||
|
if (wrapper.message != null)
|
||||||
|
{
|
||||||
|
if (context.get().getSender() != null)
|
||||||
|
{
|
||||||
|
consumer.accept(ServerPlayerWrapper.getWrapper(context.get().getSender()), wrapper.message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
consumer.accept(null, wrapper.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.get().setPacketHandled(true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPluginPacketClient(NetworkMessage message)
|
||||||
|
{
|
||||||
|
#if MC_VER >= MC_1_20_2
|
||||||
|
PLUGIN_CHANNEL.send(new MessageWrapper(message), PacketDistributor.SERVER.noArg());
|
||||||
|
#else // < 1.20.2
|
||||||
|
PLUGIN_CHANNEL.send(PacketDistributor.SERVER.noArg(), new MessageWrapper(message));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPluginPacketServer(ServerPlayer serverPlayer, NetworkMessage message)
|
||||||
|
{
|
||||||
|
#if MC_VER >= MC_1_20_2
|
||||||
|
PLUGIN_CHANNEL.send(new MessageWrapper(message), PacketDistributor.PLAYER.with(serverPlayer));
|
||||||
|
#else // < 1.20.2
|
||||||
|
PLUGIN_CHANNEL.send(PacketDistributor.PLAYER.with(() -> serverPlayer), new MessageWrapper(message));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forge doesn't support using abstract classes
|
||||||
|
@SuppressWarnings({"ClassCanBeRecord", "RedundantSuppression"})
|
||||||
|
public static class MessageWrapper
|
||||||
|
{
|
||||||
|
public final NetworkMessage message;
|
||||||
|
|
||||||
|
public MessageWrapper(NetworkMessage message)
|
||||||
|
{
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,16 +3,20 @@ package com.seibel.distanthorizons.forge;
|
|||||||
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
||||||
import com.seibel.distanthorizons.common.util.ProxyUtil;
|
import com.seibel.distanthorizons.common.util.ProxyUtil;
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.TickEvent;
|
import net.minecraftforge.event.TickEvent;
|
||||||
|
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
import net.minecraftforge.event.world.ChunkEvent;
|
import net.minecraftforge.event.world.ChunkEvent;
|
||||||
import net.minecraftforge.event.world.WorldEvent;
|
import net.minecraftforge.event.world.WorldEvent;
|
||||||
@@ -22,6 +26,13 @@ import net.minecraftforge.event.level.LevelEvent;
|
|||||||
#endif
|
#endif
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_19_4
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
#else // < 1.19.4
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.core.RegistryAccess;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MC_VER == MC_1_16_5
|
#if MC_VER == MC_1_16_5
|
||||||
import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent;
|
import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent;
|
||||||
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
|
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
|
||||||
@@ -47,7 +58,6 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
private final ServerApi serverApi = ServerApi.INSTANCE;
|
private final ServerApi serverApi = ServerApi.INSTANCE;
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
|
||||||
private final boolean isDedicated;
|
private final boolean isDedicated;
|
||||||
public static Supplier<Boolean> isGenerationThreadChecker = null;
|
public static Supplier<Boolean> isGenerationThreadChecker = null;
|
||||||
|
|
||||||
@@ -57,6 +67,10 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
public void registerEvents()
|
public void registerEvents()
|
||||||
{
|
{
|
||||||
MinecraftForge.EVENT_BUS.register(this);
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
|
if (this.isDedicated)
|
||||||
|
{
|
||||||
|
ForgePluginPacketSender.setPacketHandler(ServerApi.INSTANCE::pluginMessageReceived);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -111,7 +125,7 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
{
|
{
|
||||||
if (GetEventLevel(event) instanceof ServerLevel)
|
if (GetEventLevel(event) instanceof ServerLevel)
|
||||||
{
|
{
|
||||||
this.serverApi.serverLevelLoadEvent(this.getServerLevelWrapper((ServerLevel) GetEventLevel(event)));
|
this.serverApi.serverLevelLoadEvent(getServerLevelWrapper((ServerLevel) GetEventLevel(event)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +139,7 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
{
|
{
|
||||||
if (GetEventLevel(event) instanceof ServerLevel)
|
if (GetEventLevel(event) instanceof ServerLevel)
|
||||||
{
|
{
|
||||||
this.serverApi.serverLevelUnloadEvent(this.getServerLevelWrapper((ServerLevel) GetEventLevel(event)));
|
this.serverApi.serverLevelUnloadEvent(getServerLevelWrapper((ServerLevel) GetEventLevel(event)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,13 +151,25 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
|
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
|
||||||
this.serverApi.serverChunkLoadEvent(chunk, levelWrapper);
|
this.serverApi.serverChunkLoadEvent(chunk, levelWrapper);
|
||||||
}
|
}
|
||||||
@SubscribeEvent
|
|
||||||
public void serverChunkSaveEvent(ChunkEvent.Unload event)
|
|
||||||
{
|
|
||||||
ILevelWrapper levelWrapper = ProxyUtil.getLevelWrapper(GetEventLevel(event));
|
|
||||||
|
|
||||||
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
|
@SubscribeEvent
|
||||||
this.serverApi.serverChunkSaveEvent(chunk, levelWrapper);
|
public void playerLoggedInEvent(PlayerEvent.PlayerLoggedInEvent event)
|
||||||
|
{
|
||||||
|
this.serverApi.serverPlayerJoinEvent(getServerPlayerWrapper(event));
|
||||||
|
}
|
||||||
|
@SubscribeEvent
|
||||||
|
public void playerLoggedOutEvent(PlayerEvent.PlayerLoggedOutEvent event)
|
||||||
|
{
|
||||||
|
this.serverApi.serverPlayerDisconnectEvent(getServerPlayerWrapper(event));
|
||||||
|
}
|
||||||
|
@SubscribeEvent
|
||||||
|
public void playerChangedDimensionEvent(PlayerEvent.PlayerChangedDimensionEvent event)
|
||||||
|
{
|
||||||
|
this.serverApi.serverPlayerLevelChangeEvent(
|
||||||
|
getServerPlayerWrapper(event),
|
||||||
|
getServerLevelWrapper(event.getFrom(), event),
|
||||||
|
getServerLevelWrapper(event.getTo(), event)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -155,4 +181,20 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
private static ServerLevelWrapper getServerLevelWrapper(ServerLevel level) { return ServerLevelWrapper.getWrapper(level); }
|
private static ServerLevelWrapper getServerLevelWrapper(ServerLevel level) { return ServerLevelWrapper.getWrapper(level); }
|
||||||
|
|
||||||
|
|
||||||
|
private static ServerLevelWrapper getServerLevelWrapper(ResourceKey<Level> resourceKey, PlayerEvent event)
|
||||||
|
{
|
||||||
|
//noinspection DataFlowIssue (possible NPE after getServer())
|
||||||
|
return getServerLevelWrapper(event.getEntity().getServer().getLevel(resourceKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServerPlayerWrapper getServerPlayerWrapper(PlayerEvent event) {
|
||||||
|
return ServerPlayerWrapper.getWrapper(
|
||||||
|
#if MC_VER >= MC_1_19_2
|
||||||
|
(ServerPlayer) event.getEntity()
|
||||||
|
#else
|
||||||
|
(ServerPlayer) event.getPlayer()
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-6
@@ -22,6 +22,10 @@ package com.seibel.distanthorizons.forge.mixins.client;
|
|||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
#if MC_VER < MC_1_19_4
|
#if MC_VER < MC_1_19_4
|
||||||
import com.mojang.math.Matrix4f;
|
import com.mojang.math.Matrix4f;
|
||||||
|
import net.minecraft.client.Camera;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
#else
|
#else
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
@@ -34,13 +38,9 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
|||||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
import net.minecraft.client.Camera;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.client.renderer.GameRenderer;
|
|
||||||
import net.minecraft.client.renderer.LevelRenderer;
|
import net.minecraft.client.renderer.LevelRenderer;
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
@@ -50,7 +50,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_17_1
|
#if MC_VER < MC_1_17_1
|
||||||
import org.lwjgl.opengl.GL15;
|
import org.lwjgl.opengl.GL15;
|
||||||
|
|||||||
+18
-2
@@ -2,6 +2,8 @@ package com.seibel.distanthorizons.forge.mixins.client;
|
|||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
|
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
|
||||||
import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
|
import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
|
import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
|
||||||
@@ -11,7 +13,9 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
|||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.client.gui.screens.TitleScreen;
|
import net.minecraft.client.gui.screens.TitleScreen;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
@@ -73,11 +77,23 @@ public class MixinMinecraft
|
|||||||
&& SelfUpdater.onStart()
|
&& SelfUpdater.onStart()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
runnable = () -> {
|
runnable = () ->
|
||||||
|
{
|
||||||
|
String versionId;
|
||||||
|
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
|
||||||
|
if (updateBranch == EDhApiUpdateBranch.STABLE)
|
||||||
|
{
|
||||||
|
versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
versionId = GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha");
|
||||||
|
}
|
||||||
|
|
||||||
Minecraft.getInstance().setScreen(new UpdateModScreen(
|
Minecraft.getInstance().setScreen(new UpdateModScreen(
|
||||||
// TODO: Change to runnable, instead of tittle screen
|
// TODO: Change to runnable, instead of tittle screen
|
||||||
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
|
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
|
||||||
(Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()) : GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
|
versionId
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.seibel.distanthorizons.forge.mixins.server;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.commonMixins.MixinChunkMapCommon;
|
||||||
|
import net.minecraft.server.level.ChunkMap;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(ChunkMap.class)
|
||||||
|
public class MixinChunkMap
|
||||||
|
{
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static final String CHUNK_SERIALIZER_WRITE
|
||||||
|
= "Lnet/minecraft/world/level/chunk/storage/ChunkSerializer;write(" +
|
||||||
|
"Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/ChunkAccess;)" +
|
||||||
|
"Lnet/minecraft/nbt/CompoundTag;";
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
ServerLevel level;
|
||||||
|
|
||||||
|
// firing at INVOKE causes issues with C2ME and is probably unnecessary since we
|
||||||
|
// don't need the chunk(s) before MC has finished saving them
|
||||||
|
@Inject(method = "save", at = @At(value = "RETURN", target = CHUNK_SERIALIZER_WRITE))
|
||||||
|
private void onChunkSave(ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
|
||||||
|
{ MixinChunkMapCommon.onChunkSave(this.level, chunk, ci); }
|
||||||
|
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020-2023 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.forge.mixins.server;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.IMixinServerPlayer;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraftforge.common.util.ITeleporter;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
|
||||||
|
@Mixin(ServerPlayer.class)
|
||||||
|
public class MixinServerPlayer implements IMixinServerPlayer
|
||||||
|
{
|
||||||
|
@Unique
|
||||||
|
@Nullable
|
||||||
|
private volatile ServerLevel distantHorizons$dimensionChangeDestination;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public ServerLevel distantHorizons$getDimensionChangeDestination()
|
||||||
|
{
|
||||||
|
return this.distantHorizons$dimensionChangeDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At("HEAD"), method = "changeDimension", remap = false)
|
||||||
|
public void changeDimension(ServerLevel destination, ITeleporter teleporter, CallbackInfoReturnable<Entity> cir)
|
||||||
|
{
|
||||||
|
this.distantHorizons$dimensionChangeDestination = destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_20_1
|
||||||
|
@Inject(at = @At("RETURN"), method = "setServerLevel")
|
||||||
|
public void setServerLevel(ServerLevel level, CallbackInfo ci)
|
||||||
|
#else
|
||||||
|
@Inject(at = @At("RETURN"), method = "setLevel")
|
||||||
|
public void setLevel(ServerLevel level, CallbackInfo ci)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
this.distantHorizons$dimensionChangeDestination = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,7 +5,9 @@
|
|||||||
"mixins": [
|
"mixins": [
|
||||||
"server.MixinUtilBackgroundThread",
|
"server.MixinUtilBackgroundThread",
|
||||||
"server.MixinChunkGenerator",
|
"server.MixinChunkGenerator",
|
||||||
"server.MixinTFChunkGenerator"
|
"server.MixinTFChunkGenerator",
|
||||||
|
"server.MixinChunkMap",
|
||||||
|
"server.MixinServerPlayer"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinClientPacketListener",
|
"client.MixinClientPacketListener",
|
||||||
|
|||||||
+3
-4
@@ -5,8 +5,8 @@ org.gradle.caching=true
|
|||||||
|
|
||||||
# Mod Info
|
# Mod Info
|
||||||
mod_name=DistantHorizons
|
mod_name=DistantHorizons
|
||||||
mod_version=2.1.0-a
|
mod_version=2.2.2-a-dev
|
||||||
api_version=2.0.0
|
api_version=3.0.0
|
||||||
maven_group=com.seibel.distanthorizons
|
maven_group=com.seibel.distanthorizons
|
||||||
mod_readable_name=Distant Horizons
|
mod_readable_name=Distant Horizons
|
||||||
mod_description=This mod generates and renders simplified terrain beyond the normal view distance at a low performance cost. Allowing you to see much farther without turning your game into a slideshow.
|
mod_description=This mod generates and renders simplified terrain beyond the normal view distance at a low performance cost. Allowing you to see much farther without turning your game into a slideshow.
|
||||||
@@ -31,7 +31,6 @@ fastutil_version=8.2.1
|
|||||||
|
|
||||||
# Minecraft related libraries (included in MC's jar)
|
# Minecraft related libraries (included in MC's jar)
|
||||||
log4j_version=2.23.1
|
log4j_version=2.23.1
|
||||||
netty_version=4.1.94.Final
|
|
||||||
lwjgl_version=3.3.1
|
lwjgl_version=3.3.1
|
||||||
joml_version=1.10.2
|
joml_version=1.10.2
|
||||||
|
|
||||||
@@ -49,7 +48,7 @@ versionStr=
|
|||||||
|
|
||||||
# This defines what MC version Intellij will use for the preprocessor
|
# This defines what MC version Intellij will use for the preprocessor
|
||||||
# and what version is used automatically by build and run commands
|
# and what version is used automatically by build and run commands
|
||||||
mcVer=1.20.6
|
mcVer=1.21.1
|
||||||
|
|
||||||
# Defines the maximum amount of memory Minecraft is allowed when run in a development environment
|
# Defines the maximum amount of memory Minecraft is allowed when run in a development environment
|
||||||
#minecraftMemoryJavaArg="-Xmx4G"
|
#minecraftMemoryJavaArg="-Xmx4G"
|
||||||
+22
-46
@@ -11,41 +11,17 @@ architectury {
|
|||||||
neoForge()
|
neoForge()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this is already defined in the main settings.gradle file, why doesn't it work unless also defined here? (If compiling does work without this block feel free to remove)
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
name "Neoforge"
|
|
||||||
url "https://maven.neoforged.net/releases/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//loom {
|
|
||||||
// forge {
|
|
||||||
// convertAccessWideners.set(true)
|
|
||||||
// extraAccessWideners.add("lod.accesswidener")
|
|
||||||
// mixinConfigs("DistantHorizons.mixins.json")
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
loom {
|
loom {
|
||||||
silentMojangMappingsLicense() // Shut the licencing warning
|
silentMojangMappingsLicense() // Shut the licencing warning
|
||||||
accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
||||||
|
|
||||||
neoForge {
|
neoForge {
|
||||||
// Access wideners are now defined in the `remapJar.atAccessWideners`
|
// Access wideners are defined in the `remapJar.atAccessWideners`
|
||||||
// convertAccessWideners = true
|
|
||||||
// extraAccessWideners.add loom.accessWidenerPath.get().asFile.name
|
|
||||||
|
|
||||||
// Mixins are now defined in the `mods.toml`
|
// Mixins are defined in the `mods.toml`
|
||||||
// mixinConfigs = [
|
|
||||||
// "DistantHorizons.mixins.json"
|
|
||||||
// ]
|
|
||||||
}
|
}
|
||||||
mixin {
|
mixin {
|
||||||
// Mixins are now defined in the `mods.toml`
|
// Mixins are defined in the `mods.toml`
|
||||||
// mixinConfigs = [
|
|
||||||
// "DistantHorizons.mixins.json"
|
|
||||||
// ]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// "runs" isn't required, but when we do need it then it can be useful
|
// "runs" isn't required, but when we do need it then it can be useful
|
||||||
@@ -53,26 +29,22 @@ loom {
|
|||||||
client {
|
client {
|
||||||
client()
|
client()
|
||||||
setConfigName("NeoForge Client")
|
setConfigName("NeoForge Client")
|
||||||
ideConfigGenerated(true)
|
ideConfigGenerated(false)
|
||||||
runDir("../run")
|
runDir("../run/client")
|
||||||
// vmArgs("-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg)
|
vmArgs("-Dio.netty.leakDetection.level=advanced")
|
||||||
|
programArgs("--username", "Dev")
|
||||||
}
|
}
|
||||||
server {
|
server {
|
||||||
server()
|
server()
|
||||||
setConfigName("NeoForge Server")
|
setConfigName("NeoForge Server")
|
||||||
ideConfigGenerated(true)
|
ideConfigGenerated(false)
|
||||||
runDir("../run")
|
runDir("../run/server")
|
||||||
|
vmArgs("-Dio.netty.leakDetection.level=advanced")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remapJar {
|
|
||||||
inputFile = shadowJar.archiveFile
|
|
||||||
dependsOn shadowJar
|
|
||||||
// classifier null
|
|
||||||
|
|
||||||
atAccessWideners.add("distanthorizons.accesswidener")
|
|
||||||
}
|
|
||||||
|
|
||||||
def addMod(path, enabled) {
|
def addMod(path, enabled) {
|
||||||
if (enabled == "2")
|
if (enabled == "2")
|
||||||
@@ -80,21 +52,24 @@ def addMod(path, enabled) {
|
|||||||
else if (enabled == "1")
|
else if (enabled == "1")
|
||||||
dependencies { modCompileOnly(path) }
|
dependencies { modCompileOnly(path) }
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||||
mappings loom.layered() {
|
mappings loom.layered()
|
||||||
|
{
|
||||||
// Mojmap mappings
|
// Mojmap mappings
|
||||||
officialMojangMappings()
|
officialMojangMappings()
|
||||||
// Parchment mappings (it adds parameter mappings & javadoc)
|
// Parchment mappings (it adds parameter mappings & javadoc)
|
||||||
parchment("org.parchmentmc.data:parchment-${rootProject.parchment_version}@zip")
|
parchment("org.parchmentmc.data:parchment-${rootProject.parchment_version}@zip")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Neoforge
|
// Neoforge
|
||||||
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
|
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
|
||||||
addMod("curse.maven:TerraFirmaCraft-302973:4616004", rootProject.enable_terrafirmacraft)
|
addMod("curse.maven:TerraFirmaCraft-302973:4616004", rootProject.enable_terrafirmacraft)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
task deleteResources(type: Delete) {
|
task deleteResources(type: Delete) {
|
||||||
delete file("build/resources/main")
|
delete file("build/resources/main")
|
||||||
}
|
}
|
||||||
@@ -113,14 +88,15 @@ tasks.named('runClient') {
|
|||||||
finalizedBy(deleteResources)
|
finalizedBy(deleteResources)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remapJar {
|
||||||
|
inputFile = shadowJar.archiveFile
|
||||||
|
dependsOn shadowJar
|
||||||
|
|
||||||
|
atAccessWideners.add("distanthorizons.accesswidener")
|
||||||
|
}
|
||||||
|
|
||||||
sourcesJar {
|
sourcesJar {
|
||||||
def commonSources = project(":common").sourcesJar
|
def commonSources = project(":common").sourcesJar
|
||||||
dependsOn commonSources
|
dependsOn commonSources
|
||||||
from commonSources.archiveFile.map { zipTree(it) }
|
from commonSources.archiveFile.map { zipTree(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
//components.java {
|
|
||||||
// withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
|
|
||||||
// skip()
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|||||||
+48
-101
@@ -28,14 +28,13 @@ import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
|||||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
|
||||||
//import io.netty.buffer.ByteBuf;
|
|
||||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
@@ -47,8 +46,6 @@ import net.neoforged.neoforge.event.level.LevelEvent;
|
|||||||
import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;
|
import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
|
||||||
//import net.neoforged.network.NetworkRegistry;
|
|
||||||
//import net.neoforged.network.simple.SimpleChannel;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
@@ -63,6 +60,8 @@ import org.lwjgl.opengl.GL32;
|
|||||||
import net.neoforged.neoforge.event.TickEvent;
|
import net.neoforged.neoforge.event.TickEvent;
|
||||||
#else
|
#else
|
||||||
import net.neoforged.neoforge.client.event.ClientTickEvent;
|
import net.neoforged.neoforge.client.event.ClientTickEvent;
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -91,7 +90,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
public void registerEvents()
|
public void registerEvents()
|
||||||
{
|
{
|
||||||
NeoForge.EVENT_BUS.register(this);
|
NeoForge.EVENT_BUS.register(this);
|
||||||
setupNetworkingListeners();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -135,12 +133,12 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClientLevel clientLevel = (ClientLevel) level;
|
ClientLevel clientLevel = (ClientLevel) level;
|
||||||
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel);
|
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel, true);
|
||||||
// TODO this causes a crash due to level being set to null somewhere
|
// TODO this causes a crash due to level being set to null somewhere
|
||||||
ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper);
|
ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper);
|
||||||
}
|
}
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void clientLevelUnloadEvent(LevelEvent.Load event)
|
public void clientLevelUnloadEvent(LevelEvent.Unload event)
|
||||||
{
|
{
|
||||||
LOGGER.info("level unload");
|
LOGGER.info("level unload");
|
||||||
|
|
||||||
@@ -164,32 +162,56 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void rightClickBlockEvent(PlayerInteractEvent.RightClickBlock event)
|
public void rightClickBlockEvent(PlayerInteractEvent.RightClickBlock event)
|
||||||
{
|
{
|
||||||
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
|
if (MC.clientConnectedToDedicatedServer())
|
||||||
{
|
{
|
||||||
return;
|
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// executor to prevent locking up the render/event thread
|
||||||
|
// if the getChunk() takes longer than expected
|
||||||
|
// (which can be caused by certain mods)
|
||||||
|
ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
|
||||||
|
if (executor != null)
|
||||||
|
{
|
||||||
|
executor.execute(() ->
|
||||||
|
{
|
||||||
|
//LOGGER.trace("interact or block place event at blockPos: " + event.getPos());
|
||||||
|
|
||||||
|
LevelAccessor level = event.getLevel();
|
||||||
|
ChunkAccess chunk = level.getChunk(event.getPos());
|
||||||
|
this.onBlockChangeEvent(level, chunk);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//LOGGER.trace("interact or block place event at blockPos: " + event.getPos());
|
|
||||||
|
|
||||||
LevelAccessor level = event.getLevel();
|
|
||||||
|
|
||||||
ChunkAccess chunk = level.getChunk(event.getPos());
|
|
||||||
this.onBlockChangeEvent(level, chunk);
|
|
||||||
}
|
}
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void leftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event)
|
public void leftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event)
|
||||||
{
|
{
|
||||||
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
|
if (MC.clientConnectedToDedicatedServer())
|
||||||
{
|
{
|
||||||
return;
|
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// executor to prevent locking up the render/event thread
|
||||||
|
// if the getChunk() takes longer than expected
|
||||||
|
// (which can be caused by certain mods)
|
||||||
|
ThreadPoolExecutor executor = ThreadPoolUtil.getFileHandlerExecutor();
|
||||||
|
if (executor != null)
|
||||||
|
{
|
||||||
|
executor.execute(() ->
|
||||||
|
{
|
||||||
|
//LOGGER.trace("break or block attack at blockPos: " + event.getPos());
|
||||||
|
|
||||||
|
LevelAccessor level = event.getLevel();
|
||||||
|
ChunkAccess chunk = level.getChunk(event.getPos());
|
||||||
|
this.onBlockChangeEvent(level, chunk);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//LOGGER.trace("break or block attack at blockPos: " + event.getPos());
|
|
||||||
|
|
||||||
LevelAccessor level = event.getLevel();
|
|
||||||
|
|
||||||
ChunkAccess chunk = level.getChunk(event.getPos());
|
|
||||||
this.onBlockChangeEvent(level, chunk);
|
|
||||||
}
|
}
|
||||||
private void onBlockChangeEvent(LevelAccessor level, ChunkAccess chunk)
|
private void onBlockChangeEvent(LevelAccessor level, ChunkAccess chunk)
|
||||||
{
|
{
|
||||||
@@ -198,22 +220,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void clientChunkLoadEvent(ChunkEvent.Load event)
|
|
||||||
{
|
|
||||||
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
|
|
||||||
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), wrappedLevel);
|
|
||||||
SharedApi.INSTANCE.chunkLoadEvent(chunk, wrappedLevel);
|
|
||||||
}
|
|
||||||
@SubscribeEvent
|
|
||||||
public void clientChunkUnloadEvent(ChunkEvent.Unload event)
|
|
||||||
{
|
|
||||||
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
|
|
||||||
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), wrappedLevel);
|
|
||||||
SharedApi.INSTANCE.chunkUnloadEvent(chunk, wrappedLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==============//
|
//==============//
|
||||||
// key bindings //
|
// key bindings //
|
||||||
@@ -236,65 +242,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============//
|
|
||||||
// networking //
|
|
||||||
//============//
|
|
||||||
|
|
||||||
public static void setupNetworkingListeners()
|
|
||||||
{
|
|
||||||
// multiversePluginChannel = NetworkRegistry.newSimpleChannel(
|
|
||||||
// new ResourceLocation(ModInfo.NETWORKING_RESOURCE_NAMESPACE, ModInfo.MULTIVERSE_PLUGIN_NAMESPACE),
|
|
||||||
// // network protocol version
|
|
||||||
// () -> ModInfo.MULTIVERSE_PLUGIN_PROTOCOL_VERSION +"",
|
|
||||||
// // client accepted versions
|
|
||||||
// ForgeClientProxy::isReceivedProtocolVersionAcceptable,
|
|
||||||
// // server accepted versions
|
|
||||||
// ForgeClientProxy::isReceivedProtocolVersionAcceptable
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// multiversePluginChannel.registerMessage(0/*should be incremented for each simple channel we listen to*/, ByteBuf.class,
|
|
||||||
// // encoder
|
|
||||||
// (pack, friendlyByteBuf) -> { },
|
|
||||||
// // decoder
|
|
||||||
// (friendlyByteBuf) -> friendlyByteBuf.asByteBuf(),
|
|
||||||
// // message consumer
|
|
||||||
// (nettyByteBuf, contextRef) ->
|
|
||||||
// {
|
|
||||||
// ClientApi.INSTANCE.serverMessageReceived(nettyByteBuf);
|
|
||||||
// contextRef.get().setPacketHandled(true);
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isReceivedProtocolVersionAcceptable(String versionString)
|
|
||||||
{
|
|
||||||
if (versionString.toLowerCase().contains("allowvanilla"))
|
|
||||||
{
|
|
||||||
// allow using networking on vanilla servers
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (versionString.toLowerCase().contains("absent"))
|
|
||||||
{
|
|
||||||
// allow using networking even if DH isn't installed on the server
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// DH is installed on the server, check if the version is valid to use
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int version = Integer.parseInt(versionString);
|
|
||||||
return ModInfo.MULTIVERSE_PLUGIN_PROTOCOL_VERSION == version;
|
|
||||||
}
|
|
||||||
catch (NumberFormatException ignored)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===========//
|
//===========//
|
||||||
// rendering //
|
// rendering //
|
||||||
//===========//
|
//===========//
|
||||||
|
|||||||
@@ -22,7 +22,11 @@ package com.seibel.distanthorizons.neoforge;
|
|||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
||||||
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
|
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
@@ -30,6 +34,7 @@ import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.ModChecker;
|
|||||||
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.OptifineAccessor;
|
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.OptifineAccessor;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.neoforged.bus.api.EventPriority;
|
||||||
import net.neoforged.bus.api.IEventBus;
|
import net.neoforged.bus.api.IEventBus;
|
||||||
import net.neoforged.fml.ModLoadingContext;
|
import net.neoforged.fml.ModLoadingContext;
|
||||||
import net.neoforged.fml.common.Mod;
|
import net.neoforged.fml.common.Mod;
|
||||||
@@ -38,6 +43,7 @@ import net.neoforged.fml.event.lifecycle.FMLDedicatedServerSetupEvent;
|
|||||||
import net.neoforged.neoforge.common.NeoForge;
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
import net.neoforged.neoforge.event.RegisterCommandsEvent;
|
import net.neoforged.neoforge.event.RegisterCommandsEvent;
|
||||||
import net.neoforged.neoforge.event.server.ServerStartingEvent;
|
import net.neoforged.neoforge.event.server.ServerStartingEvent;
|
||||||
|
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@@ -53,19 +59,46 @@ import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
|
|||||||
* check out the ClientProxy.
|
* check out the ClientProxy.
|
||||||
*/
|
*/
|
||||||
@Mod(ModInfo.ID)
|
@Mod(ModInfo.ID)
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class NeoforgeMain extends AbstractModInitializer
|
public class NeoforgeMain extends AbstractModInitializer
|
||||||
{
|
{
|
||||||
public NeoforgeMain(IEventBus eventBus)
|
public NeoforgeMain(IEventBus eventBus)
|
||||||
{
|
{
|
||||||
eventBus.addListener((FMLClientSetupEvent e) -> this.onInitializeClient());
|
eventBus.addListener((FMLClientSetupEvent e) -> {
|
||||||
eventBus.addListener((FMLDedicatedServerSetupEvent e) -> this.onInitializeServer());
|
this.onInitializeClient();
|
||||||
|
eventBus.addListener(this::registerNetworkingClient);
|
||||||
|
});
|
||||||
|
eventBus.addListener((FMLDedicatedServerSetupEvent e) -> {
|
||||||
|
this.onInitializeServer();
|
||||||
|
eventBus.addListener(this::registerNetworkingServer);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// networking //
|
||||||
|
//============//
|
||||||
|
public void registerNetworkingClient(RegisterPayloadHandlersEvent event)
|
||||||
|
{
|
||||||
|
NeoforgePluginPacketSender.setPacketHandler(event, ClientApi.INSTANCE::pluginMessageReceived);
|
||||||
|
}
|
||||||
|
public void registerNetworkingServer(RegisterPayloadHandlersEvent event)
|
||||||
|
{
|
||||||
|
NeoforgePluginPacketSender.setPacketHandler(event, ServerApi.INSTANCE::pluginMessageReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IEventProxy createServerProxy(boolean isDedicated) { return new NeoforgeServerProxy(isDedicated); }
|
protected IEventProxy createServerProxy(boolean isDedicated) { return new NeoforgeServerProxy(isDedicated); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createInitialBindings() { SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); }
|
protected void createInitialBindings()
|
||||||
|
{
|
||||||
|
SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
|
||||||
|
SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new NeoforgePluginPacketSender());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IEventProxy createClientProxy() { return new NeoforgeClientProxy(); }
|
protected IEventProxy createClientProxy() { return new NeoforgeClientProxy(); }
|
||||||
@@ -83,6 +116,20 @@ public class NeoforgeMain extends AbstractModInitializer
|
|||||||
// TODO fix potential null pointer
|
// TODO fix potential null pointer
|
||||||
() -> (client, parent) -> GetConfigScreen.getScreen(parent));
|
() -> (client, parent) -> GetConfigScreen.getScreen(parent));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
if (Config.Client.Advanced.Logging.showModCompatibilityWarningsOnStartup.get())
|
||||||
|
{
|
||||||
|
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
|
||||||
|
if (modChecker.isModLoaded("alexscaves"))
|
||||||
|
{
|
||||||
|
String message =
|
||||||
|
// orange text
|
||||||
|
"\u00A76" + "Distant Horizons: Alex's Cave detected." + "\u00A7r\n" +
|
||||||
|
"You may have to change Alex's config for DH to render. ";
|
||||||
|
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -100,7 +147,7 @@ public class NeoforgeMain extends AbstractModInitializer
|
|||||||
@Override
|
@Override
|
||||||
protected void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler)
|
protected void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler)
|
||||||
{
|
{
|
||||||
NeoForge.EVENT_BUS.addListener((ServerStartingEvent e) -> { eventHandler.accept(e.getServer()); });
|
NeoForge.EVENT_BUS.addListener(EventPriority.HIGH, (ServerStartingEvent e) -> { eventHandler.accept(e.getServer()); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
package com.seibel.distanthorizons.neoforge;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.CommonPacketPayload;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.NetworkMessage;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.neoforged.neoforge.network.PacketDistributor;
|
||||||
|
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||||
|
import net.neoforged.neoforge.network.registration.PayloadRegistrar;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class NeoforgePluginPacketSender extends AbstractPluginPacketSender
|
||||||
|
{
|
||||||
|
private static BiConsumer<IServerPlayerWrapper, NetworkMessage> packetConsumer;
|
||||||
|
|
||||||
|
public static void setPacketHandler(RegisterPayloadHandlersEvent event, Consumer<NetworkMessage> consumer)
|
||||||
|
{
|
||||||
|
setPacketHandler(event, (player, buffer) -> consumer.accept(buffer));
|
||||||
|
}
|
||||||
|
public static void setPacketHandler(RegisterPayloadHandlersEvent event, BiConsumer<IServerPlayerWrapper, NetworkMessage> consumer)
|
||||||
|
{
|
||||||
|
packetConsumer = consumer;
|
||||||
|
|
||||||
|
PayloadRegistrar registrar = event.registrar("1").optional();
|
||||||
|
registrar.playBidirectional(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec(), (payload, context) ->
|
||||||
|
{
|
||||||
|
ServerPlayerWrapper serverPlayer = Optional.of(context.player())
|
||||||
|
.map(player -> player instanceof ServerPlayer ? (ServerPlayer) player : null)
|
||||||
|
.map(ServerPlayerWrapper::getWrapper)
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (payload.message() != null)
|
||||||
|
{
|
||||||
|
packetConsumer.accept(serverPlayer, payload.message());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPluginPacketClient(NetworkMessage message)
|
||||||
|
{
|
||||||
|
PacketDistributor.sendToServer(new CommonPacketPayload(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPluginPacketServer(ServerPlayer serverPlayer, NetworkMessage message)
|
||||||
|
{
|
||||||
|
PacketDistributor.sendToPlayer(serverPlayer, new CommonPacketPayload(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+32
-6
@@ -3,15 +3,20 @@ package com.seibel.distanthorizons.neoforge;
|
|||||||
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
||||||
import com.seibel.distanthorizons.common.util.ProxyUtil;
|
import com.seibel.distanthorizons.common.util.ProxyUtil;
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.neoforged.neoforge.common.NeoForge;
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
|
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
|
||||||
import net.neoforged.neoforge.event.level.ChunkEvent;
|
import net.neoforged.neoforge.event.level.ChunkEvent;
|
||||||
import net.neoforged.neoforge.event.level.LevelEvent;
|
import net.neoforged.neoforge.event.level.LevelEvent;
|
||||||
import net.neoforged.bus.api.SubscribeEvent;
|
import net.neoforged.bus.api.SubscribeEvent;
|
||||||
@@ -122,13 +127,25 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
|
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
|
||||||
this.serverApi.serverChunkLoadEvent(chunk, levelWrapper);
|
this.serverApi.serverChunkLoadEvent(chunk, levelWrapper);
|
||||||
}
|
}
|
||||||
@SubscribeEvent
|
|
||||||
public void serverChunkSaveEvent(ChunkEvent.Unload event)
|
|
||||||
{
|
|
||||||
ILevelWrapper levelWrapper = ProxyUtil.getLevelWrapper(GetEventLevel(event));
|
|
||||||
|
|
||||||
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
|
@SubscribeEvent
|
||||||
this.serverApi.serverChunkSaveEvent(chunk, levelWrapper);
|
public void playerLoggedInEvent(PlayerEvent.PlayerLoggedInEvent event)
|
||||||
|
{
|
||||||
|
this.serverApi.serverPlayerJoinEvent(getServerPlayerWrapper(event));
|
||||||
|
}
|
||||||
|
@SubscribeEvent
|
||||||
|
public void playerLoggedOutEvent(PlayerEvent.PlayerLoggedOutEvent event)
|
||||||
|
{
|
||||||
|
this.serverApi.serverPlayerDisconnectEvent(getServerPlayerWrapper(event));
|
||||||
|
}
|
||||||
|
@SubscribeEvent
|
||||||
|
public void playerChangedDimensionEvent(PlayerEvent.PlayerChangedDimensionEvent event)
|
||||||
|
{
|
||||||
|
this.serverApi.serverPlayerLevelChangeEvent(
|
||||||
|
getServerPlayerWrapper(event),
|
||||||
|
getServerLevelWrapper(event.getFrom(), event),
|
||||||
|
getServerLevelWrapper(event.getTo(), event)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -138,6 +155,15 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
//================//
|
//================//
|
||||||
|
|
||||||
private static ServerLevelWrapper getServerLevelWrapper(ServerLevel level) { return ServerLevelWrapper.getWrapper(level); }
|
private static ServerLevelWrapper getServerLevelWrapper(ServerLevel level) { return ServerLevelWrapper.getWrapper(level); }
|
||||||
|
private static ServerLevelWrapper getServerLevelWrapper(ResourceKey<Level> resourceKey, PlayerEvent event)
|
||||||
|
{
|
||||||
|
//noinspection DataFlowIssue (possible NPE after getServer())
|
||||||
|
return getServerLevelWrapper(event.getEntity().getServer().getLevel(resourceKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServerPlayerWrapper getServerPlayerWrapper(PlayerEvent event)
|
||||||
|
{
|
||||||
|
return ServerPlayerWrapper.getWrapper((ServerPlayer) event.getEntity());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+10
-1
@@ -1,8 +1,11 @@
|
|||||||
package com.seibel.distanthorizons.neoforge.mixins.client;
|
package com.seibel.distanthorizons.neoforge.mixins.client;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
@@ -10,10 +13,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
@Mixin(ClientPacketListener.class)
|
@Mixin(ClientPacketListener.class)
|
||||||
public class MixinClientPacketListener
|
public class MixinClientPacketListener
|
||||||
{
|
{
|
||||||
|
@Shadow
|
||||||
|
private ClientLevel level;
|
||||||
// TODO update fabric version as well
|
// TODO update fabric version as well
|
||||||
|
|
||||||
@Inject(method = "handleLogin", at = @At("RETURN"))
|
@Inject(method = "handleLogin", at = @At("RETURN"))
|
||||||
void onHandleLoginEnd(CallbackInfo ci) { ClientApi.INSTANCE.onClientOnlyConnected(); }
|
void onHandleLoginEnd(CallbackInfo ci)
|
||||||
|
{
|
||||||
|
ClientApi.INSTANCE.onClientOnlyConnected();
|
||||||
|
ClientApi.INSTANCE.clientLevelLoadEvent(ClientLevelWrapper.getWrapper(this.level, true));
|
||||||
|
}
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_4
|
#if MC_VER < MC_1_19_4
|
||||||
@Inject(method = "cleanup", at = @At("HEAD"))
|
@Inject(method = "cleanup", at = @At("HEAD"))
|
||||||
|
|||||||
+10
-4
@@ -24,6 +24,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||||||
#if MC_VER < MC_1_19_4
|
#if MC_VER < MC_1_19_4
|
||||||
import com.mojang.math.Matrix4f;
|
import com.mojang.math.Matrix4f;
|
||||||
#else
|
#else
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
import com.seibel.distanthorizons.neoforge.NeoforgeClientProxy;
|
import com.seibel.distanthorizons.neoforge.NeoforgeClientProxy;
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
@@ -36,7 +37,6 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
|||||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.client.renderer.LevelRenderer;
|
import net.minecraft.client.renderer.LevelRenderer;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
@@ -98,7 +98,6 @@ public class MixinLevelRenderer
|
|||||||
private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f projectionMatrix, Matrix4f frustumMatrix, CallbackInfo callback)
|
private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f projectionMatrix, Matrix4f frustumMatrix, CallbackInfo callback)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
// get MC's model view and projection matrices
|
|
||||||
#if MC_VER == MC_1_16_5
|
#if MC_VER == MC_1_16_5
|
||||||
// get the matrices from the OpenGL fixed pipeline
|
// get the matrices from the OpenGL fixed pipeline
|
||||||
float[] mcProjMatrixRaw = new float[16];
|
float[] mcProjMatrixRaw = new float[16];
|
||||||
@@ -120,15 +119,21 @@ public class MixinLevelRenderer
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
float frameTime;
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
frameTime = Minecraft.getInstance().getFrameTime();
|
||||||
|
#else
|
||||||
|
frameTime = Minecraft.getInstance().getTimer().getRealtimeDeltaTicks();
|
||||||
|
#endif
|
||||||
|
|
||||||
// only render before solid blocks
|
// only render before solid blocks
|
||||||
if (renderType.equals(RenderType.solid()))
|
if (renderType.equals(RenderType.solid()))
|
||||||
{
|
{
|
||||||
ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, Minecraft.getInstance().getFrameTime());
|
ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, frameTime);
|
||||||
}
|
}
|
||||||
else if (renderType.equals(RenderType.translucent()))
|
else if (renderType.equals(RenderType.translucent()))
|
||||||
{
|
{
|
||||||
ClientApi.INSTANCE.renderDeferredLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, Minecraft.getInstance().getFrameTime());
|
ClientApi.INSTANCE.renderDeferredLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, frameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
|
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
|
||||||
@@ -154,4 +159,5 @@ public class MixinLevelRenderer
|
|||||||
ChunkWrapper.syncedUpdateClientLightStatus();
|
ChunkWrapper.syncedUpdateClientLightStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-2
@@ -8,6 +8,7 @@ import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
|
|||||||
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
|
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
|
||||||
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
|
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.screens.TitleScreen;
|
import net.minecraft.client.gui.screens.TitleScreen;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@@ -75,11 +76,23 @@ public class MixinMinecraft
|
|||||||
&& SelfUpdater.onStart()
|
&& SelfUpdater.onStart()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
runnable = () -> {
|
runnable = () ->
|
||||||
|
{
|
||||||
|
String versionId;
|
||||||
|
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
|
||||||
|
if (updateBranch == EDhApiUpdateBranch.STABLE)
|
||||||
|
{
|
||||||
|
versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
versionId = GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha");
|
||||||
|
}
|
||||||
|
|
||||||
Minecraft.getInstance().setScreen(new UpdateModScreen(
|
Minecraft.getInstance().setScreen(new UpdateModScreen(
|
||||||
// TODO: Change to runnable, instead of tittle screen
|
// TODO: Change to runnable, instead of tittle screen
|
||||||
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
|
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
|
||||||
(Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()) : GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
|
versionId
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-7
@@ -23,16 +23,13 @@ import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
|
|||||||
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
|
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
import net.minecraft.client.gui.screens.OptionsScreen;
|
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
import net.minecraft.network.chat.TranslatableComponent;
|
import net.minecraft.network.chat.TranslatableComponent;
|
||||||
#endif
|
#endif
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
@@ -41,11 +38,20 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
#if MC_VER == MC_1_20_6
|
#if MC_VER >= MC_1_20_6
|
||||||
import net.minecraft.client.gui.layouts.LinearLayout;
|
import net.minecraft.client.gui.layouts.LinearLayout;
|
||||||
import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
|
import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
import net.minecraft.client.gui.screens.OptionsScreen;
|
||||||
|
#else
|
||||||
|
import net.minecraft.client.gui.screens.options.OptionsScreen;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a button to the menu to goto the config
|
* Adds a button to the menu to goto the config
|
||||||
*
|
*
|
||||||
@@ -57,13 +63,18 @@ public class MixinOptionsScreen extends Screen
|
|||||||
{
|
{
|
||||||
/** Texture used for the config opening button */
|
/** Texture used for the config opening button */
|
||||||
@Unique
|
@Unique
|
||||||
private static final ResourceLocation ICON_TEXTURE = new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
|
private static final ResourceLocation ICON_TEXTURE =
|
||||||
|
#if MC_VER < MC_1_21_1
|
||||||
|
new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
|
||||||
|
#else
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private TexturedButtonWidget optionsButton = null;
|
private TexturedButtonWidget optionsButton = null;
|
||||||
|
|
||||||
#if MC_VER == MC_1_20_6
|
#if MC_VER >= MC_1_20_6
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
protected HeaderAndFooterLayout layout;
|
protected HeaderAndFooterLayout layout;
|
||||||
@@ -93,7 +104,6 @@ public class MixinOptionsScreen extends Screen
|
|||||||
|
|
||||||
// add the button to the correct location in the UI
|
// add the button to the correct location in the UI
|
||||||
// TODO is there a better way to do this instead of using access transformers to inject into the exact UI elements?
|
// TODO is there a better way to do this instead of using access transformers to inject into the exact UI elements?
|
||||||
// TODO is there a way we can put the button on the left side of the FOV bar like before?
|
|
||||||
LinearLayout layout = (LinearLayout) this.layout.headerFrame.children.get(0).child;
|
LinearLayout layout = (LinearLayout) this.layout.headerFrame.children.get(0).child;
|
||||||
|
|
||||||
// determine how wide the other option buttons are so we can put our botton to the left of them all
|
// determine how wide the other option buttons are so we can put our botton to the left of them all
|
||||||
|
|||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
package com.seibel.distanthorizons.neoforge.mixins.server;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.commonMixins.MixinChunkMapCommon;
|
||||||
|
import net.minecraft.server.level.ChunkMap;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(ChunkMap.class)
|
||||||
|
public class MixinChunkMap
|
||||||
|
{
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static final String CHUNK_SERIALIZER_WRITE
|
||||||
|
= "Lnet/minecraft/world/level/chunk/storage/ChunkSerializer;write(" +
|
||||||
|
"Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/ChunkAccess;)" +
|
||||||
|
"Lnet/minecraft/nbt/CompoundTag;";
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
ServerLevel level;
|
||||||
|
|
||||||
|
// firing at INVOKE causes issues with C2ME and is probably unnecessary since we
|
||||||
|
// don't need the chunk(s) before MC has finished saving them
|
||||||
|
@Inject(method = "save", at = @At(value = "RETURN", target = CHUNK_SERIALIZER_WRITE))
|
||||||
|
private void onChunkSave(ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
|
||||||
|
{ MixinChunkMapCommon.onChunkSave(this.level, chunk, ci); }
|
||||||
|
|
||||||
|
}
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020-2023 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.neoforge.mixins.server;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.IMixinServerPlayer;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_21_1
|
||||||
|
import net.minecraft.world.level.portal.DimensionTransition;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@Mixin(ServerPlayer.class)
|
||||||
|
public class MixinServerPlayer implements IMixinServerPlayer
|
||||||
|
{
|
||||||
|
@Unique
|
||||||
|
@Nullable
|
||||||
|
private ServerLevel distantHorizons$dimensionChangeDestination;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public ServerLevel distantHorizons$getDimensionChangeDestination()
|
||||||
|
{
|
||||||
|
return this.distantHorizons$dimensionChangeDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At("HEAD"), method = "changeDimension")
|
||||||
|
#if MC_VER >= MC_1_21_1
|
||||||
|
public void changeDimension(DimensionTransition dimensionTransition, CallbackInfoReturnable<Entity> cir)
|
||||||
|
{
|
||||||
|
this.distantHorizons$dimensionChangeDestination = dimensionTransition.newLevel();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
public void changeDimension(ServerLevel destination, CallbackInfoReturnable<Entity> cir)
|
||||||
|
{
|
||||||
|
this.distantHorizons$dimensionChangeDestination = destination;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_20_1
|
||||||
|
@Inject(at = @At("RETURN"), method = "setServerLevel")
|
||||||
|
public void setServerLevel(ServerLevel level, CallbackInfo ci)
|
||||||
|
#else
|
||||||
|
@Inject(at = @At("RETURN"), method = "setLevel")
|
||||||
|
public void setLevel(ServerLevel level, CallbackInfo ci)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
this.distantHorizons$dimensionChangeDestination = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,7 +5,9 @@
|
|||||||
"mixins": [
|
"mixins": [
|
||||||
"server.MixinUtilBackgroundThread",
|
"server.MixinUtilBackgroundThread",
|
||||||
"server.MixinChunkGenerator",
|
"server.MixinChunkGenerator",
|
||||||
"server.MixinTFChunkGenerator"
|
"server.MixinTFChunkGenerator",
|
||||||
|
"server.MixinChunkMap",
|
||||||
|
"server.MixinServerPlayer"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinClientPacketListener",
|
"client.MixinClientPacketListener",
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# Usage: .\verifyall.ps1 [forge|fabric|whatever to put before ":classes"]
|
||||||
|
|
||||||
|
param (
|
||||||
|
[string]$prefix
|
||||||
|
)
|
||||||
|
|
||||||
|
# Clear the screen
|
||||||
|
Clear-Host
|
||||||
|
|
||||||
|
# Define an array to hold completed builds with color information
|
||||||
|
$completedBuilds = @()
|
||||||
|
|
||||||
|
# Get all version properties files
|
||||||
|
$versionFiles = Get-ChildItem -Path "./versionProperties/" -Filter "*.properties"
|
||||||
|
|
||||||
|
foreach ($versionFile in $versionFiles) {
|
||||||
|
$version = [System.IO.Path]::GetFileNameWithoutExtension($versionFile.Name)
|
||||||
|
|
||||||
|
# Run the gradle command
|
||||||
|
$gradleCommand = ".\gradlew $($prefix)classes -PmcVer=$version"
|
||||||
|
$process = Start-Process -FilePath "cmd.exe" -ArgumentList "/c $gradleCommand" -NoNewWindow -PassThru -Wait
|
||||||
|
|
||||||
|
# Determine the result color
|
||||||
|
if ($process.ExitCode -eq 0) {
|
||||||
|
$color = "Green"
|
||||||
|
} else {
|
||||||
|
$color = "Red"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print the result with formatting
|
||||||
|
$versionLength = $version.Length
|
||||||
|
$topChars = ("^" * $versionLength)
|
||||||
|
$bottomChars = ("=" * $versionLength)
|
||||||
|
|
||||||
|
Write-Host "# $topChars" -ForegroundColor $color
|
||||||
|
Write-Host "# $version" -ForegroundColor $color
|
||||||
|
Write-Host "# $bottomChars" -ForegroundColor $color
|
||||||
|
Write-Host
|
||||||
|
|
||||||
|
# Add result to completed builds with color
|
||||||
|
$completedBuilds += @{ Version = $version; Color = $color }
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run clean and classes gradle tasks
|
||||||
|
Start-Process -FilePath "cmd.exe" -ArgumentList "/c .\gradlew clean" -NoNewWindow -Wait
|
||||||
|
Start-Process -FilePath "cmd.exe" -ArgumentList "/c .\gradlew classes" -NoNewWindow -Wait
|
||||||
|
|
||||||
|
# Print build results
|
||||||
|
Write-Host
|
||||||
|
Write-Host "Build results:"
|
||||||
|
|
||||||
|
foreach ($build in $completedBuilds) {
|
||||||
|
Write-Host $build.Version -ForegroundColor $build.Color -NoNewline
|
||||||
|
Write-Host " " -NoNewline # Add a space between versions
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host # End the line after all versions are printed
|
||||||
Executable
+43
@@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Usage: ./verifyall.sh [forge|fabric|whatever to put before ":classes"]
|
||||||
|
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
prefix="$1:"
|
||||||
|
fi
|
||||||
|
|
||||||
|
clear
|
||||||
|
trap "echo; exit" INT
|
||||||
|
|
||||||
|
declare -a completed_builds
|
||||||
|
for version in $(ls ./versionProperties/); do
|
||||||
|
version=${version%".properties"}
|
||||||
|
|
||||||
|
result=""
|
||||||
|
if ./gradlew "$prefix"classes -PmcVer=$version; then
|
||||||
|
result+="\e[1;32m"
|
||||||
|
echo -ne "\e[1;32m"
|
||||||
|
else
|
||||||
|
result+="\e[1;31m"
|
||||||
|
echo -ne "\e[1;31m"
|
||||||
|
fi
|
||||||
|
result+=$version
|
||||||
|
result+="\e[0m"
|
||||||
|
|
||||||
|
version_length=${#version}
|
||||||
|
top_chars=$(printf '^%.0s' $(seq 1 $version_length))
|
||||||
|
bottom_chars=$(printf '=%.0s' $(seq 1 $version_length))
|
||||||
|
echo "# $top_chars"
|
||||||
|
echo "# $version"
|
||||||
|
echo "# $bottom_chars"
|
||||||
|
echo -e "\e[0m"
|
||||||
|
|
||||||
|
completed_builds+=($result)
|
||||||
|
done
|
||||||
|
|
||||||
|
./gradlew clean
|
||||||
|
./gradlew classes
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo -e "\e[1mBuild results:\e[0m"
|
||||||
|
echo -e "${completed_builds[*]}"
|
||||||
@@ -7,6 +7,9 @@ accessWidenerVersion=1_16
|
|||||||
builds_for=fabric,forge
|
builds_for=fabric,forge
|
||||||
embed_joml=true
|
embed_joml=true
|
||||||
|
|
||||||
|
# Netty
|
||||||
|
netty_version=4.1.25.Final
|
||||||
|
|
||||||
# Fabric loader
|
# Fabric loader
|
||||||
fabric_loader_version=0.14.24
|
fabric_loader_version=0.14.24
|
||||||
fabric_api_version=0.42.0+1.16
|
fabric_api_version=0.42.0+1.16
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ accessWidenerVersion=1_17
|
|||||||
builds_for=fabric,forge
|
builds_for=fabric,forge
|
||||||
embed_joml=true
|
embed_joml=true
|
||||||
|
|
||||||
|
# Netty
|
||||||
|
netty_version=4.1.25.Final
|
||||||
|
|
||||||
# Fabric loader
|
# Fabric loader
|
||||||
fabric_loader_version=0.14.24
|
fabric_loader_version=0.14.24
|
||||||
fabric_api_version=0.46.1+1.17
|
fabric_api_version=0.46.1+1.17
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user