Compare commits
624 Commits
| 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 | |||
| 71ca26bba9 | |||
| fb46820b1f | |||
| 75a51be28c | |||
| a66e4ba157 | |||
| f2b9e428d3 | |||
| 5b2497b9d4 | |||
| e78424def4 | |||
| e2c94de6e6 | |||
| a786678bcb | |||
| daa3caf684 | |||
| 5991aa42d9 | |||
| ff6a5aae69 | |||
| 80d9b4540b | |||
| 4998991ebe | |||
| 14343569fe | |||
| be6cc5ff4e | |||
| 0ad3391bea | |||
| 582d998e2e | |||
| c00ee26075 | |||
| 4c9f70a52f | |||
| 29481bc123 | |||
| e274c9e004 | |||
| 73988f0308 | |||
| c4a9e7a2a7 | |||
| af6dca6e5e | |||
| a49720a221 | |||
| 12a66e70c9 | |||
| 00d8aa356b | |||
| d40d94a565 | |||
| c1f798793e | |||
| 8fe4ad454c | |||
| 17022f2df2 | |||
| 7fa4bc35f6 | |||
| 85df9c5ef4 | |||
| 45d4f390a9 | |||
| 0d35a3ea8e | |||
| e7b60b7562 | |||
| 2615177907 | |||
| 6f87e22048 | |||
| a83d7e2a26 | |||
| 8a2182e238 | |||
| d45455092c | |||
| da18469fd4 | |||
| 6b5bae9bee | |||
| 7c07c1e5bd | |||
| e29a7786e4 | |||
| 4ddb9659f5 | |||
| e74b8c89ba | |||
| 1b536e4aef | |||
| 55a837ca5e | |||
| 94cba6cf67 | |||
| 335f11acd3 | |||
| b55b560cce | |||
| d87a152052 | |||
| 294685df00 | |||
| 2642b7a9a4 | |||
| 45594e4e47 | |||
| 54cd1a2e48 | |||
| a20fb982ec | |||
| db5a9c7c84 | |||
| 2508efdd91 | |||
| 184d61e637 | |||
| 06ea56767f | |||
| 1f6e137759 | |||
| c7cf7885ae | |||
| 8e98444887 | |||
| 9bfe2e8233 | |||
| 4852720e14 | |||
| 21f4adc769 | |||
| 3b10ca5809 | |||
| f39d156b11 | |||
| 6cc8284747 | |||
| 6254f7156f | |||
| 0fa03701a4 | |||
| 49125cae47 | |||
| 3298857d0c | |||
| d939cbeb96 | |||
| 54d254be73 | |||
| d433fdea62 | |||
| ffa1c54ff3 | |||
| 019ac6dec3 | |||
| 08d3da47f4 | |||
| 348ac2b734 | |||
| fe014b4985 | |||
| b7f6f3b900 | |||
| 3c76ed71d8 | |||
| 5de1998913 | |||
| 05c0f030cb | |||
| bd85329589 | |||
| da0f4ae326 | |||
| b37e568372 | |||
| b1c6a5c1d4 | |||
| 8222126e8f | |||
| b5b888c69f | |||
| 85f6b8320b | |||
| 6c4740e8aa | |||
| ffda83c25d | |||
| 18859d22a8 | |||
| befa3b375e | |||
| a96c08cad4 | |||
| d7f789c402 | |||
| ed28bcd0ba | |||
| 982ae0c0a0 | |||
| d17897f276 | |||
| e21eb61335 | |||
| c49f385e3c | |||
| c0ccef7e82 | |||
| 55e5c64c68 | |||
| da72f783ed | |||
| 8a9bfa3d33 | |||
| 82937d840a | |||
| c1bd358502 | |||
| a8a22fd9fe | |||
| adb70857fe | |||
| a680596b3e | |||
| b2986ec782 | |||
| f40f7afab3 | |||
| 59555d1ca8 | |||
| 0584b0e593 | |||
| 220ac89ad8 | |||
| 6e2eb7d1ac | |||
| 69483067b4 | |||
| c815591565 | |||
| f82b7ec608 | |||
| 23a107682c | |||
| 26da69c875 | |||
| 8f2df2396d | |||
| dbc9cbb418 | |||
| 09c788e495 | |||
| 9af71ac0ea | |||
| 2db20f8f24 | |||
| 2c9827c227 | |||
| 825b1ab4db | |||
| c61faac06c | |||
| 6b442f03c1 | |||
| 10ab638643 | |||
| d349d0c453 | |||
| e5c948ce9c | |||
| c51255f379 | |||
| e8e56b66a3 | |||
| 634d8a5b52 | |||
| b621c9fb8d | |||
| 5bbeceee56 | |||
| 696f84a064 | |||
| 5c13ff8960 | |||
| e102cd78cd | |||
| ee78920a88 | |||
| 138972cf18 | |||
| 1bda767cd7 | |||
| cf1402edb9 | |||
| 778144a553 | |||
| c5a782acba | |||
| 2008ea2b0c | |||
| fcca51a8d9 | |||
| 3cc663ee95 | |||
| 52f15a86fd | |||
| 734bb4afb8 | |||
| 9cd48fb5d7 | |||
| cd5c3d9f13 | |||
| 73ba1c8b56 | |||
| 8199b4408a | |||
| c00e3d7393 | |||
| 5d60251da0 | |||
| 855d707b3e | |||
| 592a1c3601 | |||
| da280db0f8 | |||
| 0f349461d9 | |||
| 0ee6673e68 | |||
| 8bedb3dbaa | |||
| ea0e24b430 | |||
| baf464aa02 | |||
| 51d83d803a | |||
| 2b3244159b | |||
| 9255c22d0e | |||
| cd35461df6 | |||
| 4d573c4aea | |||
| 40580e81c2 | |||
| 1a279b90be | |||
| e34203fe3d | |||
| a59f359133 | |||
| c83d02c30c | |||
| d01573b03e | |||
| b1fb74539f | |||
| 870c0f68d3 | |||
| 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
|
||||||
|
|||||||
+4
-1
@@ -34,6 +34,9 @@ build.properties
|
|||||||
|
|
||||||
# Sqlite databases
|
# Sqlite databases
|
||||||
*.sqlite
|
*.sqlite
|
||||||
|
*.sqlite-journal
|
||||||
|
*.sqlite-shm
|
||||||
|
*.sqlite-wal
|
||||||
|
|
||||||
# Don't add access transformers to git as it's dynamically generated
|
# Don't add access transformers to git as they're dynamically generated
|
||||||
accesstransformer.cfg
|
accesstransformer.cfg
|
||||||
|
|||||||
+10
-5
@@ -1,6 +1,6 @@
|
|||||||
# use Eclipse's JDK
|
# use Eclipse's JDK
|
||||||
# The ci should always use a unix(-like) OS to work
|
# The ci should always use a unix(-like) OS to work
|
||||||
image: eclipse-temurin:17
|
image: eclipse-temurin:21
|
||||||
|
|
||||||
# all stages need to be defined here
|
# all stages need to be defined here
|
||||||
# TODO: Make stages depend on what is in versionProperties
|
# TODO: Make stages depend on what is in versionProperties
|
||||||
@@ -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"]
|
- 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:
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
[submodule "coreSubProjects"]
|
[submodule "coreSubProjects"]
|
||||||
path = coreSubProjects
|
path = coreSubProjects
|
||||||
url = https://gitlab.com/jeseibel/distant-horizons-core.git
|
url = https://gitlab.com/jeseibel/distant-horizons-core.git
|
||||||
@@ -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>
|
||||||
@@ -1,18 +1,16 @@
|
|||||||
# <img src="https://gitlab.com/jeseibel/distant-horizons-core/-/raw/main/_Misc%20Files/logo%20files/LOD%20logo%20flat%20-%20with%20boarder.png" width="32"> Distant Horizons
|
# <img src="https://gitlab.com/jeseibel/distant-horizons-core/-/raw/main/_Misc%20Files/logo%20files/LOD%20logo%20flat%20-%20with%20boarder.png" width="32"> Distant Horizons
|
||||||
|
_See farther without turning your game into a slide show._
|
||||||
|
|
||||||
> A mod that adds a Level of Detail System to Minecraft
|
<br>
|
||||||
|
|
||||||
|
|
||||||
# What is Distant Horizons?
|
# What is Distant Horizons?
|
||||||
|
|
||||||
Distant Horizons is a Minecraft mod that adds a Level Of Detail (LOD) system to\
|
Distant Horizons is a mod which implements a [Level of Detail](https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics)) system to Minecraft.\
|
||||||
render simplified chunks outside the normal render distance\
|
This allows for far greater render distances without harming performance by gradually lowering the quality of distant terrain.
|
||||||
allowing for an increased view distance without harming performance.
|
|
||||||
|
|
||||||
In other words: this mod lets you see farther without turning your game into a slide show.\
|
Below is a video demonstrating the system:
|
||||||
If you want to see a quick demo, check out a video covering the mod here:
|
|
||||||
|
|
||||||
<a href="https://youtu.be/_04BZ8W2bDM" target="_blank"></a>
|
<a href="https://youtu.be/SxQdbtjGEsc" target="_blank"></a>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -81,7 +79,8 @@ Modmenu: 1.16.22
|
|||||||
- 1.18.1, 1.18
|
- 1.18.1, 1.18
|
||||||
- 1.19.1, 1.19
|
- 1.19.1, 1.19
|
||||||
- 1.19.3
|
- 1.19.3
|
||||||
<br><br>
|
|
||||||
|
<br>
|
||||||
|
|
||||||
### Plugin and Library versions
|
### Plugin and Library versions
|
||||||
|
|
||||||
@@ -101,7 +100,7 @@ Java Preprocessor plugin: Manifold Preprocessor
|
|||||||
Visit https://www.oracle.com/java/technologies/downloads/ for installers.
|
Visit https://www.oracle.com/java/technologies/downloads/ for installers.
|
||||||
* Git or someway to clone git projects. <br>
|
* Git or someway to clone git projects. <br>
|
||||||
Visit https://git-scm.com/ for installers.
|
Visit https://git-scm.com/ for installers.
|
||||||
* (Not required) Any Java IDE with plugins that support Manifold, for example Intellij IDEA.
|
* (Not required) Any Java IDE with plugins that support Manifold, for example IntelliJ IDEA.
|
||||||
|
|
||||||
**If using IntelliJ:**
|
**If using IntelliJ:**
|
||||||
1. Install the Manifold plugin
|
1. Install the Manifold plugin
|
||||||
@@ -114,17 +113,14 @@ Java Preprocessor plugin: Manifold Preprocessor
|
|||||||
3. Make sure eclipse has the JDK 17 installed. (This is needed so that eclipse can run minecraft)
|
3. Make sure eclipse has the JDK 17 installed. (This is needed so that eclipse can run minecraft)
|
||||||
4. Import the project into eclipse
|
4. Import the project into eclipse
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
## Switching Versions
|
## Switching Versions
|
||||||
|
|
||||||
To switch between different Minecraft versions, change `mcVer=1.?` in the `gradle.properties` file.
|
To switch between different Minecraft versions, change `mcVer=1.?` in the `gradle.properties` file.
|
||||||
|
|
||||||
If running in an IDE, to ensure the IDE noticed the version change, run any gradle command to refresh gradle. (In IntellJ you will also need to do a gradle sync if it didn't happen automatically.)
|
If running in an IDE, to ensure the IDE noticed the version change, run any gradle command to refresh gradle.\
|
||||||
>Note: There may be a `java.nio.file.FileSystemException` thrown when running the command after switching versions. To fix it, either restart your IDE (as your IDE is probably locking a file) or use a tool like LockHunter to unlock the linked file(s). (Generally it is a lib file under `common\build\lib`, `forge\build\lib`, or `fabric\build\lib`). \
|
In IntelliJ, you will also need to do a gradle sync if it didn't happen automatically.
|
||||||
> If anyone knows how to solve this issue please let us know here: \
|
|
||||||
> https://gitlab.com/jeseibel/distant-horizons/-/issues/233
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -138,21 +134,20 @@ From the File Explorer:
|
|||||||
2. Download the core from https://gitlab.com/jeseibel/distant-horizons-core and extract into a folder called `coreSubProjects`
|
2. Download the core from https://gitlab.com/jeseibel/distant-horizons-core and extract into a folder called `coreSubProjects`
|
||||||
3. Open a terminal emulator in the project folder (On Windows you can type `cmd` in the title bar)
|
3. Open a terminal emulator in the project folder (On Windows you can type `cmd` in the title bar)
|
||||||
4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows)
|
4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows)
|
||||||
5. Merge the jars wih `./gradlew mergeJars`
|
5. Merge the jars with `./gradlew mergeJars`
|
||||||
6. The compiled jar file will be in the folder `Merged`
|
6. The compiled jar file will be in the folder `Merged`
|
||||||
|
|
||||||
From the command line:
|
From the command line:
|
||||||
1. `git clone --recurse-submodules https://gitlab.com/jeseibel/distant-horizons.git`
|
1. `git clone --recurse-submodules https://gitlab.com/jeseibel/distant-horizons.git`
|
||||||
2. `cd minecraft-lod-mod`
|
2. `cd distant-horizons`
|
||||||
3. `./gradlew assemble`
|
3. `./gradlew assemble`
|
||||||
4. `./gradlew mergeJars`
|
4. `./gradlew mergeJars`
|
||||||
5. The compiled jar file will be in the folder `Merged`
|
5. The compiled jar file will be in the folder `Merged`
|
||||||
|
|
||||||
Run tests with: `./gradlew test`
|
Run tests with: `./gradlew test`
|
||||||
|
|
||||||
>Note: You can add the arg: `-PmcVer=?` to tell gradle to build a selected MC version instead of having to modify the `gradle.properties` file. \
|
>Note: You can add the argument `-PmcVer=?` to tell gradle to build a selected MC version instead of having to modify the `gradle.properties` file.\
|
||||||
> Example: `./gradlew assemble -PmcVer=1.18.2`
|
> For example: `./gradlew assemble -PmcVer=1.18.2`
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -162,7 +157,6 @@ Run tests with: `./gradlew test`
|
|||||||
|
|
||||||
You can also locally compile the DH jars without a Java environment by using Docker. Where `<version>` is the version of Minecraft to compile for (ie `1.20.1`), or the keyword `all`. See [Versions](#minecraft-and-library-versions) for a list of all supported values.
|
You can also locally compile the DH jars without a Java environment by using Docker. Where `<version>` is the version of Minecraft to compile for (ie `1.20.1`), or the keyword `all`. See [Versions](#minecraft-and-library-versions) for a list of all supported values.
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## Other commands
|
## Other commands
|
||||||
@@ -171,6 +165,7 @@ You can also locally compile the DH jars without a Java environment by using Doc
|
|||||||
|
|
||||||
`./gradlew clean` to delete any compiled code.
|
`./gradlew clean` to delete any compiled code.
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
## Note to self
|
## Note to self
|
||||||
|
|
||||||
@@ -178,7 +173,7 @@ The Minecraft source code is NOT added to your workspace in an editable way. Min
|
|||||||
|
|
||||||
Source code uses Mojang mappings & [Parchment](https://parchmentmc.org/) mappings.
|
Source code uses Mojang mappings & [Parchment](https://parchmentmc.org/) mappings.
|
||||||
|
|
||||||
To generate the source code run `./gradlew genSources`\
|
To generate the source code run `./gradlew genSources` <br>
|
||||||
If your IDE fails to auto-detect the source jars when browsing Minecraft classes; manually select the JAR file ending with -sources.jar when prompted by your IDE. <br>
|
If your IDE fails to auto-detect the source jars when browsing Minecraft classes; manually select the JAR file ending with -sources.jar when prompted by your IDE. <br>
|
||||||
(In IntelliJ it's at the top where it says "choose sources" when browsing a Minecraft class)
|
(In IntelliJ it's at the top where it says "choose sources" when browsing a Minecraft class)
|
||||||
|
|
||||||
@@ -186,12 +181,12 @@ If your IDE fails to auto-detect the source jars when browsing Minecraft classes
|
|||||||
|
|
||||||
## Other Useful commands
|
## Other Useful commands
|
||||||
|
|
||||||
Run the standalone jar: `./gradlew run`\
|
Run the standalone jar: `./gradlew run` <br>
|
||||||
Build the standalone jar: `./gradlew core:build`\
|
Build the standalone jar: `./gradlew core:build` <br>
|
||||||
Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build`\
|
Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build` <br>
|
||||||
Only build Forge: `./gradlew fabric:assemble` or `./gradlew forge:build`\
|
Only build Forge: `./gradlew forge:assemble` or `./gradlew forge:build` <br>
|
||||||
Run the Fabric client (for debugging): `./gradlew fabric:runClient`\
|
Run the Fabric client (for debugging): `./gradlew fabric:runClient` <br>
|
||||||
Run the Forge client (for debugging): `./gradlew forge:runClient`
|
Run the Forge client (for debugging): `./gradlew forge:runClient` <br>
|
||||||
|
|
||||||
To build all versions: `./buildAll` (all builds will end up in the `Merged` folder)
|
To build all versions: `./buildAll` (all builds will end up in the `Merged` folder)
|
||||||
|
|
||||||
@@ -205,7 +200,7 @@ https://github.com/PacifistMC/Forgix
|
|||||||
LZ4 for Java (data compression)\
|
LZ4 for Java (data compression)\
|
||||||
https://github.com/lz4/lz4-java
|
https://github.com/lz4/lz4-java
|
||||||
|
|
||||||
NightConfig for Json & Toml (config handling)\
|
NightConfig for JSON & TOML (config handling)\
|
||||||
https://github.com/TheElectronWill/night-config
|
https://github.com/TheElectronWill/night-config
|
||||||
|
|
||||||
SVG Salamander for SVG support (not being used atm)\
|
SVG Salamander for SVG support (not being used atm)\
|
||||||
|
|||||||
+156
-152
@@ -2,21 +2,16 @@ plugins {
|
|||||||
id "java"
|
id "java"
|
||||||
|
|
||||||
// Plugin to put dependencies inside our final jar
|
// Plugin to put dependencies inside our final jar
|
||||||
id "com.github.johnrengelman.shadow" version '7.1.2' apply false
|
id "com.github.johnrengelman.shadow" version '8.1.1' apply false
|
||||||
|
|
||||||
// Plugin to create merged jars
|
// Plugin to create merged jars
|
||||||
id "io.github.pacifistmc.forgix" version "1.2.6"
|
id "io.github.pacifistmc.forgix" version "1.2.9"
|
||||||
|
|
||||||
// Unimined is our all in one solution to minecraft loaders
|
// Manifold preprocessor
|
||||||
// id "xyz.wagyourtail.unimined" version "1.2.0-SNAPSHOT" apply false // Unstable Release (TODO: Check back to see when the unstable branch fixes forge run without the jank)
|
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
|
||||||
id "xyz.wagyourtail.unimined" version "1.1.2-SNAPSHOT" apply false // LTS Release
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Architectury is used here only as a replacement for forge's own loom
|
||||||
// Transfers the values set in settings.gradle to the rest of the project
|
id "dev.architectury.loom" version "1.6-SNAPSHOT" apply false
|
||||||
project.gradle.ext.getProperties().each { prop ->
|
|
||||||
rootProject.ext.set(prop.key, prop.value)
|
|
||||||
// println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -32,8 +27,8 @@ def writeBuildGradlePredefine(List<String> mcVers, int mcIndex)
|
|||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n");
|
sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n");
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < mcVers.size(); i++)
|
for (int i = 0; i < mcVers.size(); i++)
|
||||||
{
|
{
|
||||||
String verStr = mcVers[i].replace(".", "_");
|
String verStr = mcVers[i].replace(".", "_");
|
||||||
@@ -54,6 +49,14 @@ def writeBuildGradlePredefine(List<String> mcVers, int mcIndex)
|
|||||||
|
|
||||||
new File(projectDir, "build.properties").text = sb.toString()
|
new File(projectDir, "build.properties").text = sb.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transfers the values set in settings.gradle to the rest of the project
|
||||||
|
project.gradle.ext.getProperties().each { prop ->
|
||||||
|
rootProject.ext.set(prop.key, prop.value)
|
||||||
|
//println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
|
||||||
|
}
|
||||||
|
// Sets up manifold stuff
|
||||||
writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
|
writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
|
||||||
|
|
||||||
|
|
||||||
@@ -61,7 +64,6 @@ writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
|
|||||||
|
|
||||||
// Sets up the version string (the name we use for our jar)
|
// Sets up the version string (the name we use for our jar)
|
||||||
rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm")
|
rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm")
|
||||||
|
|
||||||
// Forgix settings (used for merging jars)
|
// Forgix settings (used for merging jars)
|
||||||
forgix {
|
forgix {
|
||||||
group = "com.seibel.distanthorizons"
|
group = "com.seibel.distanthorizons"
|
||||||
@@ -92,7 +94,7 @@ forgix {
|
|||||||
}
|
}
|
||||||
|
|
||||||
subprojects { p ->
|
subprojects { p ->
|
||||||
// Does the same as "p == project(":common") || p == project(":fabric") || p == project(":forge") || p == project("WhateverLoaderWeAddLaterOn")"
|
// Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")"
|
||||||
// Useful later on so we dont have duplicated code
|
// Useful later on so we dont have duplicated code
|
||||||
def isMinecraftSubProject = p != project(":core") && p != project(":api")
|
def isMinecraftSubProject = p != project(":core") && p != project(":api")
|
||||||
|
|
||||||
@@ -100,79 +102,74 @@ subprojects { p ->
|
|||||||
// Apply plugins
|
// Apply plugins
|
||||||
apply plugin: "java"
|
apply plugin: "java"
|
||||||
apply plugin: "com.github.johnrengelman.shadow"
|
apply plugin: "com.github.johnrengelman.shadow"
|
||||||
if (p == project(":core"))
|
if (isMinecraftSubProject)
|
||||||
apply plugin: "application"
|
apply plugin: "systems.manifold.manifold-gradle-plugin"
|
||||||
|
|
||||||
if (isMinecraftSubProject) {
|
|
||||||
apply plugin: "xyz.wagyourtail.unimined"
|
|
||||||
|
|
||||||
unimined.minecraft(sourceSets.main, true) {
|
// Apply forge's loom
|
||||||
version = rootProject.minecraft_version
|
if ((findProject(":forge") && p == project(":forge")) ||
|
||||||
|
(findProject(":neoforge") && p == project(":neoforge"))
|
||||||
def parchmentVersionParts = rootProject.parchment_version.split(":")
|
)
|
||||||
mappings {
|
{
|
||||||
mojmap()
|
apply plugin: "dev.architectury.loom"
|
||||||
parchment(parchmentVersionParts[0], parchmentVersionParts[1])
|
|
||||||
devNamespace "mojmap"
|
|
||||||
}
|
|
||||||
|
|
||||||
runs {
|
|
||||||
config("client") {
|
|
||||||
workingDir = rootProject.file("run")
|
|
||||||
}
|
|
||||||
config("server") {
|
|
||||||
workingDir = rootProject.file("run") // TODO: When running the server, would it be a better idea to change this to a different dir?
|
|
||||||
disabled = true // TODO: Once server-side support is added, remove this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p != project(":common")) {
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
|
||||||
source(project(":common").sourceSets.main.java)
|
|
||||||
source(project(":api").sourceSets.main.java)
|
|
||||||
source(project(":core").sourceSets.main.java)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(GenerateModuleMetadata) {
|
|
||||||
enabled = false
|
// Set the manifold version (may not be required tough)
|
||||||
|
manifold {
|
||||||
|
manifoldVersion = rootProject.manifold_version
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable testing for projects that aren't the core or api project.
|
|
||||||
// If not done compiling will fail due to an issue with Manifold
|
|
||||||
if (isMinecraftSubProject) {
|
|
||||||
test {
|
|
||||||
enabled = false
|
|
||||||
}
|
|
||||||
compileTestJava {
|
|
||||||
enabled = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// set up custom configurations (configurations are a way to handle dependencies)
|
// set up custom configurations (configurations are a way to handle dependencies)
|
||||||
configurations {
|
configurations {
|
||||||
// extends the shadowJar configuration
|
// extends the shadowJar configuration
|
||||||
shadowMc // Configuration that doesn't contain coreProjects
|
shadowMe
|
||||||
|
|
||||||
// have implemented dependencies automatically embedded in the final jar
|
// have implemented dependencies automatically embedded in the final jar
|
||||||
implementation.extendsFrom(shadowMc)
|
implementation.extendsFrom(shadowMe)
|
||||||
|
|
||||||
// Add shaded libraries very early in the classpath (excluding coreProjects as that's added in a different way)
|
// Configuration fpr core & api
|
||||||
minecraftLibraries.extendsFrom(shadowMc)
|
coreProjects
|
||||||
}
|
shadowMe.extendsFrom(coreProjects)
|
||||||
|
|
||||||
|
|
||||||
// Let the application plugin know where the main class is
|
// FIXME this additional configuration is necessary because forge
|
||||||
// (This will point to a non-existent class in all sub-projects except "Core")
|
// needs forgeRuntimeLibrary, although adding it to shadowMe
|
||||||
if (p == project(":core")) {
|
// causes runtime issues where the libraries aren't properly added
|
||||||
application {
|
forgeShadowMe
|
||||||
mainClass.set("com.seibel.distanthorizons.core.jar.JarMain")
|
// this should match shadowMe pretty closely
|
||||||
|
implementation.extendsFrom(forgeShadowMe)
|
||||||
|
shadowMe.extendsFrom(forgeShadowMe)
|
||||||
|
forgeRuntimeLibrary.extendsFrom(forgeShadowMe)
|
||||||
|
|
||||||
|
|
||||||
|
if (isMinecraftSubProject && p != project(":common")) {
|
||||||
|
// Shadow common
|
||||||
|
common
|
||||||
|
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
|
||||||
|
compileClasspath.extendsFrom common
|
||||||
|
runtimeClasspath.extendsFrom common
|
||||||
|
if (findProject(":forge"))
|
||||||
|
developmentForge.extendsFrom common
|
||||||
|
if (findProject(":neoforge"))
|
||||||
|
developmentNeoForge.extendsFrom common
|
||||||
|
compileClasspath.extendsFrom coreProjects
|
||||||
|
runtimeClasspath.extendsFrom coreProjects
|
||||||
|
if (findProject(":forge"))
|
||||||
|
developmentForge.extendsFrom coreProjects
|
||||||
|
if (findProject(":neoforge"))
|
||||||
|
developmentNeoForge.extendsFrom coreProjects
|
||||||
|
|
||||||
|
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
||||||
|
// Shadow fabricLike
|
||||||
|
fabricLike
|
||||||
|
shadowFabricLike
|
||||||
|
compileClasspath.extendsFrom fabricLike
|
||||||
|
runtimeClasspath.extendsFrom fabricLike
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
//=====================//
|
//=====================//
|
||||||
// shared dependencies //
|
// shared dependencies //
|
||||||
@@ -184,41 +181,47 @@ subprojects { p ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log4j
|
// Log4j
|
||||||
// TODO: Change to shadowCore later to work in the standalone jar
|
// TODO: Change to shadowMe later to work in the standalone jar
|
||||||
// We cannot do this now as it would break Quilt
|
// We cannot do this now as it would break Quilt
|
||||||
implementation("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}")
|
implementation("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}")
|
||||||
implementation("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
|
implementation("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
|
||||||
|
|
||||||
|
// JOML
|
||||||
|
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||||
|
forgeShadowMe("org.joml:joml:${rootProject.joml_version}")
|
||||||
|
else
|
||||||
|
implementation("org.joml:joml:${rootProject.joml_version}")
|
||||||
|
|
||||||
// JUnit tests
|
// JUnit tests
|
||||||
implementation("org.junit.jupiter:junit-jupiter:5.8.2")
|
implementation("org.junit.jupiter:junit-jupiter:5.8.2")
|
||||||
implementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
implementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
||||||
implementation("junit:junit:4.13")
|
implementation("junit:junit:4.13")
|
||||||
|
|
||||||
// JOML
|
// FastUtil
|
||||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
// Note: MC 1.16 uses 8.2.1, and versions after use 8.5.12
|
||||||
shadowMc("org.joml:joml:${rootProject.joml_version}")
|
// We cannot relocate this library since we call some MC classes that reference it
|
||||||
else
|
implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}")
|
||||||
implementation("org.joml:joml:${rootProject.joml_version}")
|
|
||||||
|
|
||||||
// Compression
|
// Compression
|
||||||
shadowMc("org.lz4:lz4-java:${rootProject.lz4_version}")
|
forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4
|
||||||
|
forgeShadowMe("org.tukaani:xz:${rootProject.xz_version}") // LZMA
|
||||||
|
|
||||||
// Sqlite Database
|
// Sqlite Database
|
||||||
shadowMc("org.xerial:sqlite-jdbc:${rootProject.sqlite_jdbc_version}")
|
forgeShadowMe("org.xerial:sqlite-jdbc:${rootProject.sqlite_jdbc_version}")
|
||||||
|
|
||||||
// NightConfig (includes Toml & Json)
|
// NightConfig (includes Toml & Json)
|
||||||
shadowMc("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
|
forgeShadowMe("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
|
||||||
shadowMc("com.electronwill.night-config:json:${rootProject.nightconfig_version}")
|
forgeShadowMe("com.electronwill.night-config:json:${rootProject.nightconfig_version}")
|
||||||
|
|
||||||
// SVG (not needed atm)
|
// SVG (not needed atm)
|
||||||
//shadowMc("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}")
|
||||||
//shadowMc("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
|
||||||
shadowMc("org.lwjgl:lwjgl-jawt:${rootProject.lwjgl_version}") {
|
forgeShadowMe("org.lwjgl:lwjgl-jawt:${rootProject.lwjgl_version}") {
|
||||||
exclude group: "org.lwjgl", module: "lwjgl" // This module is imported by Minecraft so exclude it
|
exclude group: "org.lwjgl", module: "lwjgl" // This module is imported by Minecraft so exclude it
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,12 +234,11 @@ subprojects { p ->
|
|||||||
|
|
||||||
// Add core
|
// Add core
|
||||||
if (isMinecraftSubProject) {
|
if (isMinecraftSubProject) {
|
||||||
compileOnly(project(":core")) {
|
coreProjects(project(":core")) {
|
||||||
// Remove Junit test libraries
|
// Remove Junit test libraries
|
||||||
exclude group: "org.junit.jupiter", module: "junit-jupiter"
|
exclude group: "org.junit.jupiter", module: "junit-jupiter"
|
||||||
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
|
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
|
||||||
exclude group: "junit", module: "junit"
|
exclude group: "junit", module: "junit"
|
||||||
|
|
||||||
// Removed dependencies
|
// Removed dependencies
|
||||||
transitive false
|
transitive false
|
||||||
}
|
}
|
||||||
@@ -244,12 +246,11 @@ subprojects { p ->
|
|||||||
|
|
||||||
// Add the api
|
// Add the api
|
||||||
if (p != project(":api")) {
|
if (p != project(":api")) {
|
||||||
implementation(project(":api")) {
|
coreProjects(project(":api")) {
|
||||||
// Remove Junit test libraries
|
// Remove Junit test libraries
|
||||||
exclude group: "org.junit.jupiter", module: "junit-jupiter"
|
exclude group: "org.junit.jupiter", module: "junit-jupiter"
|
||||||
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
|
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
|
||||||
exclude group: "junit", module: "junit"
|
exclude group: "junit", module: "junit"
|
||||||
|
|
||||||
// Removed dependencies
|
// Removed dependencies
|
||||||
transitive false
|
transitive false
|
||||||
}
|
}
|
||||||
@@ -258,20 +259,30 @@ subprojects { p ->
|
|||||||
// Add common
|
// Add common
|
||||||
if (isMinecraftSubProject && p != project(":common")) {
|
if (isMinecraftSubProject && p != project(":common")) {
|
||||||
// Common
|
// Common
|
||||||
compileOnly(project(":common")) { transitive false }
|
common(project(":common")) { transitive false }
|
||||||
|
shadowCommon(project(":common")) { transitive false }
|
||||||
|
|
||||||
|
// FabricLike
|
||||||
|
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
||||||
|
fabricLike(project(path: ":fabricLike")) { transitive false }
|
||||||
|
shadowFabricLike(project(path: ":fabricLike")) { transitive false }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
configurations = [project.configurations.shadowMc]
|
configurations = [project.configurations.shadowMe]
|
||||||
|
|
||||||
if (isMinecraftSubProject && p != project(":common")) {
|
if (isMinecraftSubProject && p != project(":common")) {
|
||||||
|
configurations.push(project.configurations.shadowCommon) // Shadow the common subproject
|
||||||
relocate "com.seibel.distanthorizons.common", "loaderCommon.${p.name}.com.seibel.distanthorizons.common" // Move the loader files to a different location
|
relocate "com.seibel.distanthorizons.common", "loaderCommon.${p.name}.com.seibel.distanthorizons.common" // Move the loader files to a different location
|
||||||
|
|
||||||
|
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
||||||
|
configurations.push(project.configurations.shadowFabricLike) // Shadow the fabricLike subproject
|
||||||
|
relocate "com.seibel.distanthorizons.fabriclike", "loaderCommon.${p.name}.com.seibel.distanthorizons.fabriclike" // Move the loader files to a different location
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
def librariesLocation = "DistantHorizons.libraries"
|
||||||
|
|
||||||
def librariesLocation = "distanthorizons.libraries"
|
|
||||||
|
|
||||||
// LWJGL
|
// LWJGL
|
||||||
// Only ever shadow the dependencies we use otherwise some stuff would break when running on an external client
|
// Only ever shadow the dependencies we use otherwise some stuff would break when running on an external client
|
||||||
@@ -279,11 +290,11 @@ subprojects { p ->
|
|||||||
|
|
||||||
// Compression (LZ4)
|
// Compression (LZ4)
|
||||||
relocate "net.jpountz", "${librariesLocation}.jpountz"
|
relocate "net.jpountz", "${librariesLocation}.jpountz"
|
||||||
|
|
||||||
// Sqlite Database
|
// Sqlite Database
|
||||||
//At the moment, there is a bug in this library which doesnt allow it to be relocated
|
//At the moment, there is a bug in this library which doesnt allow it to be relocated
|
||||||
// relocate "org.sqlite", "${librariesLocation}.sqlite"
|
// relocate "org.sqlite", "${librariesLocation}.sqlite"
|
||||||
|
|
||||||
// JOML
|
// JOML
|
||||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||||
relocate "org.joml", "${librariesLocation}.joml"
|
relocate "org.joml", "${librariesLocation}.joml"
|
||||||
@@ -293,9 +304,10 @@ subprojects { p ->
|
|||||||
|
|
||||||
// SVG (not needed atm)
|
// SVG (not needed atm)
|
||||||
// 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()
|
||||||
}
|
}
|
||||||
@@ -305,33 +317,21 @@ subprojects { p ->
|
|||||||
|
|
||||||
// Put stuff from gradle.properties into the mod info
|
// Put stuff from gradle.properties into the mod info
|
||||||
processResources {
|
processResources {
|
||||||
duplicatesStrategy = DuplicatesStrategy.WARN
|
def resourceTargets = [ // Location of where to inject the properties
|
||||||
// Include all the resources
|
// Holds info like git commit
|
||||||
from project(":common").sourceSets.main.resources
|
// TODO: For some reason this script doesnt work with the core project
|
||||||
from project(":core").sourceSets.main.resources
|
"build_info.json",
|
||||||
from project(":api").sourceSets.main.resources
|
|
||||||
|
|
||||||
// Copy accessWideners
|
|
||||||
// FIXME: remove copyCommonLoaderResources and use this instead (and if you are removing that task, also remove copyCoreResources while your at it)
|
|
||||||
// from project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
|
||||||
// into(file(p.file("build/resources/main")))
|
|
||||||
rename "${accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
|
|
||||||
|
|
||||||
// Location of where to inject the properties
|
// Properties for each of the loaders
|
||||||
def resourceTargets = [
|
"fabric.mod.json",
|
||||||
// Holds info like git commit
|
"quilt.mod.json",
|
||||||
// TODO: For some reason this script doesnt work with the core project
|
"META-INF/mods.toml",
|
||||||
"build_info.json",
|
"META-INF/neoforge.mods.toml",
|
||||||
|
|
||||||
// Properties for each of the loaders
|
// The mixins for each of the loaders
|
||||||
"fabric.mod.json",
|
"DistantHorizons." + p.name + ".fabricLike.mixins.json"
|
||||||
"quilt.mod.json",
|
|
||||||
"META-INF/mods.toml",
|
|
||||||
|
|
||||||
// The mixins for each of the loaders
|
|
||||||
"DistantHorizons."+ p.name +".fabricLike.mixins.json"
|
|
||||||
]
|
]
|
||||||
def buildResourceTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
||||||
|
|
||||||
// Fix forge version numbering system as it is weird
|
// Fix forge version numbering system as it is weird
|
||||||
// For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"]
|
// For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"]
|
||||||
@@ -339,7 +339,7 @@ subprojects { p ->
|
|||||||
// println compatible_forgemc_versions
|
// println compatible_forgemc_versions
|
||||||
|
|
||||||
// Quilt's custom contributors system
|
// Quilt's custom contributors system
|
||||||
// has to be in the format:
|
// This has to be like
|
||||||
// "Person": "Developer", "Another person": "Developer"
|
// "Person": "Developer", "Another person": "Developer"
|
||||||
def quilt_contributors = []
|
def quilt_contributors = []
|
||||||
def mod_author_list = mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",")
|
def mod_author_list = mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",")
|
||||||
@@ -388,17 +388,15 @@ subprojects { p ->
|
|||||||
fabric_incompatibility_list : fabric_incompatibility_list,
|
fabric_incompatibility_list : fabric_incompatibility_list,
|
||||||
fabric_recommend_list : fabric_recommend_list,
|
fabric_recommend_list : fabric_recommend_list,
|
||||||
]
|
]
|
||||||
|
|
||||||
// replace any properties in the sub-projects with the values defined here
|
// replace any properties in the sub-projects with the values defined here
|
||||||
inputs.properties replaceProperties
|
inputs.properties replaceProperties
|
||||||
replaceProperties.put("project", project)
|
replaceProperties.put "project", project
|
||||||
filesMatching(resourceTargets) {
|
filesMatching(resourceTargets) {
|
||||||
expand replaceProperties
|
expand replaceProperties
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intoTargets.each { target ->
|
||||||
// copy all our resources into the loader specific resource directory
|
|
||||||
buildResourceTargets.each { target ->
|
|
||||||
if (file(target).exists()) {
|
if (file(target).exists()) {
|
||||||
copy {
|
copy {
|
||||||
from(sourceSets.main.resources) {
|
from(sourceSets.main.resources) {
|
||||||
@@ -433,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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,15 +524,17 @@ 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 {
|
||||||
dirs "${rootDir}/mods/fabric"
|
dirs "${rootDir}/mods/fabric"
|
||||||
@@ -562,7 +564,6 @@ allprojects { p ->
|
|||||||
// Set the OS lwjgl is using to the current os
|
// Set the OS lwjgl is using to the current os
|
||||||
project.ext.lwjglNatives = "natives-" + os.toFamilyName()
|
project.ext.lwjglNatives = "natives-" + os.toFamilyName()
|
||||||
|
|
||||||
// TODO: Include Minecraft in core-projects but dont include MC code stuff
|
|
||||||
dependencies { // All of these dependencies are in Vanilla Minecraft, but we need to depend on it as we arent importing Minecraft in the core
|
dependencies { // All of these dependencies are in Vanilla Minecraft, but we need to depend on it as we arent importing Minecraft in the core
|
||||||
// Imports most of lwjgl's libraries (well, only the ones that we need)
|
// Imports most of lwjgl's libraries (well, only the ones that we need)
|
||||||
implementation platform("org.lwjgl:lwjgl-bom:${rootProject.lwjgl_version}") // TODO: Use Minecraft's version for lwjgl_version (which changes in nearly every version) instead of a hard defined version for all versions
|
implementation platform("org.lwjgl:lwjgl-bom:${rootProject.lwjgl_version}") // TODO: Use Minecraft's version for lwjgl_version (which changes in nearly every version) instead of a hard defined version for all versions
|
||||||
@@ -590,27 +591,30 @@ allprojects { p ->
|
|||||||
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
||||||
implementation("com.google.common:google-collect:0.5")
|
implementation("com.google.common:google-collect:0.5")
|
||||||
implementation("com.google.guava:guava:31.1-jre")
|
implementation("com.google.guava:guava:31.1-jre")
|
||||||
implementation("it.unimi.dsi:fastutil:8.5.11")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: Remove this as no loader needs this
|
|
||||||
// - Fabric can rename which aw they use
|
|
||||||
// - (Neo)Forge converts the aw to their own at, which is stored at a different place
|
|
||||||
task copyCommonLoaderResources(type: Copy) {
|
task copyCommonLoaderResources(type: Copy) {
|
||||||
from project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
from project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
||||||
into(file(p.file("build/resources/main")))
|
into(file(p.file("build/resources/main")))
|
||||||
rename "${accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
|
rename "${accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
|
||||||
|
|
||||||
|
|
||||||
|
// Move the fabricLike mixin to its different places for each subproject
|
||||||
|
if (findProject(":fabricLike")) {
|
||||||
|
from project(":fabricLike").file("src/main/resources/DistantHorizons.fabricLike.mixins.json")
|
||||||
|
into(file(p.file("build/resources/main")))
|
||||||
|
rename "DistantHorizons.fabricLike.mixins.json", "DistantHorizons." + p.name + ".fabricLike.mixins.json"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove this later as we no longer need this. We are now including the resources in the processResources section
|
|
||||||
task copyCoreResources(type: Copy) {
|
task copyCoreResources(type: Copy) {
|
||||||
from fileTree(project(":core").file("src/main/resources"))
|
from fileTree(project(":core").file("src/main/resources"))
|
||||||
into p.file("build/resources/main")
|
into p.file("build/resources/main")
|
||||||
}
|
}
|
||||||
|
|
||||||
compileJava {
|
tasks.withType(JavaCompile) {
|
||||||
if (isMinecraftSubProject) {
|
if (isMinecraftSubProject) {
|
||||||
options.release = rootProject.java_version as Integer
|
options.release = rootProject.java_version as Integer
|
||||||
options.compilerArgs += ["-Xplugin:Manifold"]
|
options.compilerArgs += ["-Xplugin:Manifold"]
|
||||||
@@ -635,4 +639,4 @@ task cleanMergedJars() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// add cleanMergedJars to the end of the "clean" task
|
// add cleanMergedJars to the end of the "clean" task
|
||||||
tasks["clean"].finalizedBy(cleanMergedJars)
|
tasks["clean"].finalizedBy(cleanMergedJars)
|
||||||
@@ -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
|
||||||
|
|||||||
+40
-11
@@ -1,16 +1,45 @@
|
|||||||
// Use Unimined's implimentation for MC as we can use Parchment mappings in common now! :tada:
|
buildscript {
|
||||||
// With Sponge's vanilla gradle, we cannot change the mappings to anything out of mojmaps
|
configurations.configureEach {
|
||||||
unimined.minecraft {
|
resolutionStrategy {
|
||||||
fabric { // TODO: Find a way to only include the mc stuff, not fabric's loader
|
force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82'
|
||||||
loader rootProject.fabric_loader_version
|
}
|
||||||
accessWidener(project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener"))
|
|
||||||
|
|
||||||
skipInsertAw = true
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
defaultRemapJar = false
|
|
||||||
|
// temporary fix for broken spongepowered version
|
||||||
|
buildscript {
|
||||||
|
configurations.configureEach {
|
||||||
|
resolutionStrategy {
|
||||||
|
force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id "org.spongepowered.gradle.vanilla" version "0.2.1-SNAPSHOT"
|
||||||
|
}
|
||||||
|
|
||||||
|
minecraft {
|
||||||
|
accessWideners(project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener"))
|
||||||
|
version(rootProject.minecraft_version)
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
// So mixins can be written in common
|
||||||
|
compileOnly group:'org.spongepowered', name:'mixin', version:'0.8.5'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
mavenCommon(MavenPublication) {
|
||||||
|
artifactId = rootProject.mod_readable_name
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||||
|
repositories {
|
||||||
|
// Add repositories to publish to here.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+165
-12
@@ -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,9 +193,135 @@ public abstract class AbstractModInitializer
|
|||||||
LOGGER.info("Mod Post-Initialized");
|
LOGGER.info("Mod Post-Initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
private void initCommands()
|
private void initCommands()
|
||||||
{
|
{
|
||||||
// TODO
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -182,4 +335,4 @@ public abstract class AbstractModInitializer
|
|||||||
void registerEvents();
|
void registerEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
-94
@@ -1,94 +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.rendering;
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_4
|
|
||||||
import com.mojang.math.Matrix4f;
|
|
||||||
#else
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
#endif
|
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
|
||||||
import com.seibel.distanthorizons.core.util.RenderUtil;
|
|
||||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
|
||||||
import org.lwjgl.opengl.GL15;
|
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
|
|
||||||
public class SeamlessOverdraw
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Proof-of-concept experimental option, not intended for normal use. <br>
|
|
||||||
* (Poorly) replaces Minecraft's far clip plane so it lines up with DH's near clip plane.
|
|
||||||
*/
|
|
||||||
public static float[] overwriteMinecraftNearFarClipPlanes(Matrix4f minecraftProjectionMatrix, float previousPartialTicks)
|
|
||||||
{
|
|
||||||
float[] matrixFloatArray;
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_4
|
|
||||||
FloatBuffer matrixFloatBuffer = FloatBuffer.allocate(16);
|
|
||||||
minecraftProjectionMatrix.store(matrixFloatBuffer);
|
|
||||||
matrixFloatArray = matrixFloatBuffer.array();
|
|
||||||
#else
|
|
||||||
// Passing float buffers in caused native code crashes, so we are passing in a float array instead
|
|
||||||
matrixFloatArray = new float[16];
|
|
||||||
minecraftProjectionMatrix.get(matrixFloatArray);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return overwriteMinecraftNearFarClipPlanes(matrixFloatArray, previousPartialTicks);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float[] overwriteMinecraftNearFarClipPlanes(Mat4f minecraftProjectionMatrix, float previousPartialTicks)
|
|
||||||
{
|
|
||||||
return overwriteMinecraftNearFarClipPlanes(minecraftProjectionMatrix.getValuesAsArray(), previousPartialTicks);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static float[] overwriteMinecraftNearFarClipPlanes(float[] projectionMatrixFloatArray, float previousPartialTicks)
|
|
||||||
{
|
|
||||||
float dhFarClipPlane = RenderUtil.getNearClipPlaneDistanceInBlocks(previousPartialTicks);
|
|
||||||
|
|
||||||
// works for fabric, bad not for forge for some reason :/
|
|
||||||
float farClip = dhFarClipPlane * 5.1f; // magic number found via trial and error, James has no idea what it represents, except that it makes the seam between DH and vanilla rendering pretty close
|
|
||||||
float nearClip = 0.5f; // this causes issues with some vanilla rendering, specifically the wireframe around selected blocks is slightly off. Unfortunately the ratio between the near and far clip plane can't be easily modified without completely screwing up the rendering.
|
|
||||||
|
|
||||||
// these may be the wrong index locations in any version of MC other than 1.18.2
|
|
||||||
projectionMatrixFloatArray[10] = -((farClip + nearClip) / (farClip - nearClip)); // near clip plane
|
|
||||||
projectionMatrixFloatArray[11] = -((2 * farClip * nearClip) / (farClip - nearClip)); // far clip plane
|
|
||||||
|
|
||||||
|
|
||||||
return projectionMatrixFloatArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
|
||||||
// helper methods //
|
|
||||||
//================//
|
|
||||||
|
|
||||||
public static void applyLegacyProjectionMatrix(float[] projectionMatrixFloatArray)
|
|
||||||
{
|
|
||||||
int glMatrixMode = GL15.glGetInteger(GL15.GL_MATRIX_MODE);
|
|
||||||
GL15.glMatrixMode(GL15.GL_PROJECTION);
|
|
||||||
|
|
||||||
GL15.glLoadMatrixf(projectionMatrixFloatArray);
|
|
||||||
|
|
||||||
GL15.glMatrixMode(glMatrixMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+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));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+56
-53
@@ -32,6 +32,7 @@ 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.level.IDhLevel;
|
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||||
import com.seibel.distanthorizons.core.level.IDhServerLevel;
|
import com.seibel.distanthorizons.core.level.IDhServerLevel;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||||
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;
|
||||||
@@ -54,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
|
||||||
{
|
{
|
||||||
@@ -81,17 +79,56 @@ 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
|
||||||
|
public IBiomeWrapper getPlainsBiomeWrapper(ILevelWrapper levelWrapper) // TODO is there a way we could get this without the levelWrapper? it isn't necessary but would clean up the code a bit
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return BiomeWrapper.deserialize(BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING, levelWrapper);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
throw new LodUtil.AssertFailureException("Unable to parse plains resource string ["+BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING+"], error:\n " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBlockStateWrapper deserializeBlockStateWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BlockStateWrapper.deserialize(str, levelWrapper); }
|
public IBlockStateWrapper deserializeBlockStateWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BlockStateWrapper.deserialize(str, levelWrapper); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBlockStateWrapper getAirBlockStateWrapper() { return BlockStateWrapper.AIR; }
|
public IBlockStateWrapper getAirBlockStateWrapper() { return BlockStateWrapper.AIR; }
|
||||||
|
|
||||||
@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(); }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -118,7 +155,7 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MC_VER <= MC_1_20_4
|
//#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
|
||||||
@@ -142,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);
|
||||||
@@ -164,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,
|
||||||
@@ -183,16 +201,13 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
{
|
{
|
||||||
String[] expectedClassNames;
|
String[] expectedClassNames;
|
||||||
|
|
||||||
#if MC_VER <= MC_1_20_4
|
//#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);
|
||||||
}
|
}
|
||||||
@@ -210,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;
|
||||||
|
|
||||||
@@ -231,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_4
|
#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));
|
||||||
@@ -239,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
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -254,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_4
|
|
||||||
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);
|
||||||
@@ -269,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_4
|
//#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));
|
||||||
@@ -287,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,
|
||||||
@@ -302,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_4
|
|
||||||
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);
|
||||||
|
|||||||
+95
-52
@@ -32,8 +32,6 @@ import org.apache.logging.log4j.Logger;
|
|||||||
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
|
|
||||||
#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
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||||
@@ -56,16 +54,22 @@ import net.minecraft.world.level.biome.Biomes;
|
|||||||
/** This class wraps the minecraft BlockPos.Mutable (and BlockPos) class */
|
/** This class wraps the minecraft BlockPos.Mutable (and BlockPos) class */
|
||||||
public class BiomeWrapper implements IBiomeWrapper
|
public class BiomeWrapper implements IBiomeWrapper
|
||||||
{
|
{
|
||||||
|
// must be defined before AIR, otherwise a null pointer will be thrown
|
||||||
private static final Logger LOGGER = LogManager.getLogger();
|
private static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_18_2
|
#if MC_VER < MC_1_18_2
|
||||||
public static final ConcurrentMap<Biome, BiomeWrapper> WRAPPER_BY_BIOME = new ConcurrentHashMap<>();
|
public static final ConcurrentMap<Biome, BiomeWrapper> WRAPPER_BY_BIOME = new ConcurrentHashMap<>();
|
||||||
#else
|
#else
|
||||||
public static final ConcurrentMap<Holder<Biome>, BiomeWrapper> WRAPPER_BY_BIOME = new ConcurrentHashMap<>();
|
public static final ConcurrentMap<Holder<Biome>, BiomeWrapper> WRAPPER_BY_BIOME = new ConcurrentHashMap<>();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public static final String EMPTY_STRING = "EMPTY";
|
public static final ConcurrentHashMap<String, BiomeWrapper> WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>();
|
||||||
public static final BiomeWrapper EMPTY_WRAPPER = new BiomeWrapper();
|
|
||||||
|
public static final String EMPTY_BIOME_STRING = "EMPTY";
|
||||||
|
public static final BiomeWrapper EMPTY_WRAPPER = new BiomeWrapper(null, null);
|
||||||
|
|
||||||
|
public static final String PLAINS_RESOURCE_LOCATION_STRING = "minecraft:plains";
|
||||||
|
|
||||||
/** keep track of broken biomes so we don't log every time */
|
/** keep track of broken biomes so we don't log every time */
|
||||||
private static final HashSet<String> brokenResourceLocationStrings = new HashSet<>();
|
private static final HashSet<String> brokenResourceLocationStrings = new HashSet<>();
|
||||||
@@ -88,7 +92,8 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** technically final, but since it requires a method call to generate it can't be marked as such */
|
/** technically final, but since it requires a method call to generate it can't be marked as such */
|
||||||
private String serialString = null;
|
private String serialString;
|
||||||
|
private final int hashCode;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -119,14 +124,17 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
{
|
{
|
||||||
this.biome = biome;
|
this.biome = biome;
|
||||||
this.serialString = this.serialize(levelWrapper);
|
this.serialString = this.serialize(levelWrapper);
|
||||||
LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]");
|
this.hashCode = Objects.hash(this.serialString);
|
||||||
|
|
||||||
|
//LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** should only be used to create {@link BiomeWrapper#EMPTY_WRAPPER} */
|
/** should only be used to create {@link BiomeWrapper#EMPTY_WRAPPER} */
|
||||||
private BiomeWrapper()
|
private BiomeWrapper()
|
||||||
{
|
{
|
||||||
this.biome = null;
|
this.biome = null;
|
||||||
this.serialString = EMPTY_STRING;
|
this.serialString = EMPTY_BIOME_STRING;
|
||||||
|
this.hashCode = Objects.hash(this.serialString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -140,7 +148,7 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
{
|
{
|
||||||
if (this == EMPTY_WRAPPER)
|
if (this == EMPTY_WRAPPER)
|
||||||
{
|
{
|
||||||
return EMPTY_STRING;
|
return EMPTY_BIOME_STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MC_VER < MC_1_18_2
|
#if MC_VER < MC_1_18_2
|
||||||
@@ -168,7 +176,7 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() { return Objects.hash(this.getSerialString()); }
|
public int hashCode() { return this.hashCode; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSerialString() { return this.serialString; }
|
public String getSerialString() { return this.serialString; }
|
||||||
@@ -187,29 +195,31 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
|
|
||||||
public String serialize(ILevelWrapper levelWrapper)
|
public String serialize(ILevelWrapper levelWrapper)
|
||||||
{
|
{
|
||||||
if (this.serialString != null)
|
if (this.biome == null)
|
||||||
{
|
{
|
||||||
return this.serialString;
|
return EMPTY_BIOME_STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// we can't generate a serial string if the level is null
|
// we can't generate a serial string if the level is null
|
||||||
if (levelWrapper == null)
|
if (levelWrapper == null)
|
||||||
{
|
{
|
||||||
if (!emptyLevelSerializeFailLogged)
|
if (!emptyLevelSerializeFailLogged)
|
||||||
{
|
{
|
||||||
emptyLevelSerializeFailLogged = true;
|
emptyLevelSerializeFailLogged = true;
|
||||||
LOGGER.warn("Unable to serialize biome: ["+this.biome+"] because the passed in level wrapper is null. Future errors won't be logged.");
|
LOGGER.warn("Unable to serialize biome: [" + this.biome + "] because the passed in level wrapper is null. Future errors of this type won't be logged.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return EMPTY_STRING;
|
return EMPTY_BIOME_STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// generate the serial string //
|
// generate the serial string //
|
||||||
|
|
||||||
net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess();
|
Level level = (Level)levelWrapper.getWrappedMcObject();
|
||||||
|
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||||
|
|
||||||
ResourceLocation resourceLocation;
|
ResourceLocation resourceLocation;
|
||||||
#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
|
||||||
@@ -241,14 +251,18 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
return this.serialString;
|
return this.serialString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO would it be worth while to cache these objects in a ConcurrentHashMap<string, IBiomeWrapper>?
|
||||||
public static IBiomeWrapper deserialize(String resourceLocationString, ILevelWrapper levelWrapper) throws IOException
|
public static IBiomeWrapper deserialize(String resourceLocationString, ILevelWrapper levelWrapper) throws IOException
|
||||||
{
|
{
|
||||||
if (resourceLocationString.equals(EMPTY_STRING))
|
// we need the final string for the concurrent hash map later
|
||||||
|
final String finalResourceStateString = resourceLocationString;
|
||||||
|
|
||||||
|
if (resourceLocationString.equals(EMPTY_BIOME_STRING))
|
||||||
{
|
{
|
||||||
if (!emptyStringWarningLogged)
|
if (!emptyStringWarningLogged)
|
||||||
{
|
{
|
||||||
emptyStringWarningLogged = true;
|
emptyStringWarningLogged = true;
|
||||||
LOGGER.warn("[" + EMPTY_STRING + "] biome string deserialized. This may mean the level was null when a save was attempted, a file saving error, or a biome saving error. Future errors will not be logged.");
|
LOGGER.warn("[" + EMPTY_BIOME_STRING + "] biome string deserialized. This may mean the level was null when a save was attempted, a file saving error, or a biome saving error. Future errors will not be logged.");
|
||||||
}
|
}
|
||||||
return EMPTY_WRAPPER;
|
return EMPTY_WRAPPER;
|
||||||
}
|
}
|
||||||
@@ -258,53 +272,82 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
return EMPTY_WRAPPER;
|
return EMPTY_WRAPPER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (WRAPPER_BY_RESOURCE_LOCATION.containsKey(finalResourceStateString))
|
||||||
|
|
||||||
// parse the resource location
|
|
||||||
int separatorIndex = resourceLocationString.indexOf(":");
|
|
||||||
if (separatorIndex == -1)
|
|
||||||
{
|
{
|
||||||
throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "].");
|
return WRAPPER_BY_RESOURCE_LOCATION.get(finalResourceStateString);
|
||||||
}
|
}
|
||||||
ResourceLocation resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// if no wrapper is found, default to the empty wrapper
|
||||||
|
BiomeWrapper foundWrapper = EMPTY_WRAPPER;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Level level = (Level)levelWrapper.getWrappedMcObject();
|
// parse the resource location
|
||||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
int separatorIndex = resourceLocationString.indexOf(":");
|
||||||
|
if (separatorIndex == -1)
|
||||||
boolean success;
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
|
||||||
Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
|
|
||||||
success = (biome != null);
|
|
||||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
|
||||||
Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
|
|
||||||
success = (unwrappedBiome != null);
|
|
||||||
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
|
|
||||||
#else
|
|
||||||
Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
|
|
||||||
success = (unwrappedBiome != null);
|
|
||||||
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
{
|
{
|
||||||
if (!brokenResourceLocationStrings.contains(resourceLocationString))
|
throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "].");
|
||||||
{
|
|
||||||
brokenResourceLocationStrings.add(resourceLocationString);
|
|
||||||
LOGGER.warn("Unable to deserialize biome from string: [" + resourceLocationString + "]");
|
|
||||||
}
|
|
||||||
return EMPTY_WRAPPER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return getBiomeWrapper(biome, levelWrapper);
|
ResourceLocation resourceLocation;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_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)
|
||||||
|
{
|
||||||
|
throw new IOException("No Resource Location found for the string: [" + resourceLocationString + "] Error: [" + e.getMessage() + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Level level = (Level) levelWrapper.getWrappedMcObject();
|
||||||
|
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||||
|
|
||||||
|
boolean success;
|
||||||
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
|
Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
|
||||||
|
success = (biome != null);
|
||||||
|
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||||
|
Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
|
||||||
|
success = (unwrappedBiome != null);
|
||||||
|
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
|
||||||
|
#else
|
||||||
|
Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
|
||||||
|
success = (unwrappedBiome != null);
|
||||||
|
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
if (!brokenResourceLocationStrings.contains(resourceLocationString))
|
||||||
|
{
|
||||||
|
brokenResourceLocationStrings.add(resourceLocationString);
|
||||||
|
LOGGER.warn("Unable to deserialize biome from string: [" + resourceLocationString + "]");
|
||||||
|
}
|
||||||
|
return EMPTY_WRAPPER;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foundWrapper = (BiomeWrapper) getBiomeWrapper(biome, levelWrapper);
|
||||||
|
return foundWrapper;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new IOException("Failed to deserialize the string [" + finalResourceStateString + "] into a BiomeWrapper: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
finally
|
||||||
{
|
{
|
||||||
throw new IOException("Failed to deserialize the string [" + resourceLocationString + "] into a BiomeWrapper: " + e.getMessage(), e);
|
WRAPPER_BY_RESOURCE_LOCATION.putIfAbsent(finalResourceStateString, foundWrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+303
-117
@@ -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;
|
||||||
@@ -65,13 +72,15 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||||
|
|
||||||
public static final ConcurrentHashMap<BlockState, BlockStateWrapper> WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>();
|
public static final ConcurrentHashMap<BlockState, BlockStateWrapper> WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>();
|
||||||
|
public static final ConcurrentHashMap<String, BlockStateWrapper> WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public static final String AIR_STRING = "AIR";
|
public static final String AIR_STRING = "AIR";
|
||||||
public static final BlockStateWrapper AIR = new BlockStateWrapper(null, null);
|
public static final BlockStateWrapper AIR = new BlockStateWrapper(null, null);
|
||||||
|
|
||||||
// TODO: Make this changeable through the config
|
public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt";
|
||||||
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<>();
|
||||||
@@ -83,13 +92,20 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
public final BlockState blockState;
|
public final BlockState blockState;
|
||||||
/** technically final, but since it requires a method call to generate it can't be marked as such */
|
/** technically final, but since it requires a method call to generate it can't be marked as such */
|
||||||
private String serialString;
|
private String serialString;
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -121,15 +137,69 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
{
|
{
|
||||||
this.blockState = blockState;
|
this.blockState = blockState;
|
||||||
this.serialString = this.serialize(levelWrapper);
|
this.serialString = this.serialize(levelWrapper);
|
||||||
this.irisBlockMaterialId = this.calculateIrisBlockMaterialId();
|
this.hashCode = Objects.hash(this.serialString);
|
||||||
LOGGER.trace("Created BlockStateWrapper ["+this.serialString+"] for ["+blockState+"] with material ID ["+this.irisBlockMaterialId+"]");
|
this.blockMaterialId = this.calculateEDhApiBlockMaterialId().index;
|
||||||
|
|
||||||
|
// 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.
|
||||||
@@ -143,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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -196,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -245,7 +382,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() { return Objects.hash(this.getSerialString()); }
|
public int hashCode() { return this.hashCode; }
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -281,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(); }
|
||||||
@@ -334,103 +483,137 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
/** will only work if a level is currently loaded */
|
/** will only work if a level is currently loaded */
|
||||||
public static IBlockStateWrapper deserialize(String resourceStateString, ILevelWrapper levelWrapper) throws IOException
|
public static IBlockStateWrapper deserialize(String resourceStateString, ILevelWrapper levelWrapper) throws IOException
|
||||||
{
|
{
|
||||||
if (resourceStateString.equals(AIR_STRING) || resourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case
|
// we need the final string for the concurrent hash map later
|
||||||
|
final String finalResourceStateString = resourceStateString;
|
||||||
|
|
||||||
|
if (finalResourceStateString.equals(AIR_STRING) || finalResourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case
|
||||||
{
|
{
|
||||||
return AIR;
|
return AIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// attempt to use the existing wrapper
|
||||||
|
if (WRAPPER_BY_RESOURCE_LOCATION.containsKey(finalResourceStateString))
|
||||||
// try to parse out the BlockState
|
|
||||||
String blockStatePropertiesString = null; // will be null if no properties were included
|
|
||||||
int stateSeparatorIndex = resourceStateString.indexOf(STATE_STRING_SEPARATOR);
|
|
||||||
if (stateSeparatorIndex != -1)
|
|
||||||
{
|
{
|
||||||
// blockstate properties found
|
return WRAPPER_BY_RESOURCE_LOCATION.get(finalResourceStateString);
|
||||||
blockStatePropertiesString = resourceStateString.substring(stateSeparatorIndex + STATE_STRING_SEPARATOR.length());
|
|
||||||
resourceStateString = resourceStateString.substring(0, stateSeparatorIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse the resource location
|
|
||||||
int resourceSeparatorIndex = resourceStateString.indexOf(RESOURCE_LOCATION_SEPARATOR);
|
|
||||||
if (resourceSeparatorIndex == -1)
|
|
||||||
{
|
|
||||||
throw new IOException("Unable to parse Resource Location out of string: [" + resourceStateString + "].");
|
|
||||||
}
|
|
||||||
ResourceLocation resourceLocation = new ResourceLocation(resourceStateString.substring(0, resourceSeparatorIndex), resourceStateString.substring(resourceSeparatorIndex + 1));
|
|
||||||
|
|
||||||
|
|
||||||
|
// if no wrapper is found, default to air
|
||||||
// attempt to get the BlockState from all possible BlockStates
|
BlockStateWrapper foundWrapper = AIR;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// try to parse out the BlockState
|
||||||
#if MC_VER > MC_1_17_1
|
String blockStatePropertiesString = null; // will be null if no properties were included
|
||||||
// use the given level if possible, otherwise try using the currently loaded one
|
int stateSeparatorIndex = resourceStateString.indexOf(STATE_STRING_SEPARATOR);
|
||||||
Level level = (levelWrapper != null ? (Level)levelWrapper.getWrappedMcObject() : null);
|
if (stateSeparatorIndex != -1)
|
||||||
level = (level == null ? Minecraft.getInstance().level : level);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Block block;
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
|
||||||
block = Registry.BLOCK.get(resourceLocation);
|
|
||||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
|
||||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
|
||||||
block = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).get(resourceLocation);
|
|
||||||
#else
|
|
||||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
|
||||||
block = registryAccess.registryOrThrow(Registries.BLOCK).get(resourceLocation);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
if (block == null)
|
|
||||||
{
|
{
|
||||||
// shouldn't normally happen, but here to make the compiler happy
|
// blockstate properties found
|
||||||
if (!BrokenResourceLocations.contains(resourceLocation))
|
blockStatePropertiesString = resourceStateString.substring(stateSeparatorIndex + STATE_STRING_SEPARATOR.length());
|
||||||
{
|
resourceStateString = resourceStateString.substring(0, stateSeparatorIndex);
|
||||||
BrokenResourceLocations.add(resourceLocation);
|
}
|
||||||
LOGGER.warn("Unable to find BlockState with the resourceLocation [" + resourceLocation + "] and properties: [" + blockStatePropertiesString + "]. Air will be used instead, some data may be lost.");
|
|
||||||
}
|
// parse the resource location
|
||||||
return AIR;
|
int separatorIndex = resourceStateString.indexOf(RESOURCE_LOCATION_SEPARATOR);
|
||||||
|
if (separatorIndex == -1)
|
||||||
|
{
|
||||||
|
throw new IOException("Unable to parse Resource Location out of string: [" + resourceStateString + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceLocation resourceLocation;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_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)
|
||||||
|
{
|
||||||
|
throw new IOException("No Resource Location found for the string: [" + resourceStateString + "] Error: [" + e.getMessage() + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// attempt to find the blockstate from all possibilities
|
|
||||||
BlockState foundState = null;
|
|
||||||
if (blockStatePropertiesString != null)
|
|
||||||
{
|
|
||||||
List<BlockState> possibleStateList = block.getStateDefinition().getPossibleStates();
|
|
||||||
for (BlockState possibleState : possibleStateList)
|
|
||||||
{
|
|
||||||
String possibleStatePropertiesString = serializeBlockStateProperties(possibleState);
|
|
||||||
if (possibleStatePropertiesString.equals(blockStatePropertiesString))
|
|
||||||
{
|
|
||||||
foundState = possibleState;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// use the default if no state was found or given
|
// attempt to get the BlockState from all possible BlockStates
|
||||||
if (foundState == null)
|
try
|
||||||
{
|
{
|
||||||
if (blockStatePropertiesString != null)
|
|
||||||
|
#if MC_VER > MC_1_17_1
|
||||||
|
Level level = (Level)Objects.requireNonNull(levelWrapper.getWrappedMcObject());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Block block;
|
||||||
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
|
block = Registry.BLOCK.get(resourceLocation);
|
||||||
|
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||||
|
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||||
|
block = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).get(resourceLocation);
|
||||||
|
#else
|
||||||
|
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||||
|
block = registryAccess.registryOrThrow(Registries.BLOCK).get(resourceLocation);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
if (block == null)
|
||||||
{
|
{
|
||||||
// we should have found a blockstate, but didn't
|
// shouldn't normally happen, but here to make the compiler happy
|
||||||
if (!BrokenResourceLocations.contains(resourceLocation))
|
if (!BrokenResourceLocations.contains(resourceLocation))
|
||||||
{
|
{
|
||||||
BrokenResourceLocations.add(resourceLocation);
|
BrokenResourceLocations.add(resourceLocation);
|
||||||
LOGGER.warn("Unable to find BlockState for Block [" + resourceLocation + "] with properties: [" + blockStatePropertiesString + "]. Using the default block state.");
|
LOGGER.warn("Unable to find BlockState with the resourceLocation [" + resourceLocation + "] and properties: [" + blockStatePropertiesString + "]. Air will be used instead, some data may be lost.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return AIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// attempt to find the blockstate from all possibilities
|
||||||
|
BlockState foundState = null;
|
||||||
|
if (blockStatePropertiesString != null)
|
||||||
|
{
|
||||||
|
List<BlockState> possibleStateList = block.getStateDefinition().getPossibleStates();
|
||||||
|
for (BlockState possibleState : possibleStateList)
|
||||||
|
{
|
||||||
|
String possibleStatePropertiesString = serializeBlockStateProperties(possibleState);
|
||||||
|
if (possibleStatePropertiesString.equals(blockStatePropertiesString))
|
||||||
|
{
|
||||||
|
foundState = possibleState;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foundState = block.defaultBlockState();
|
// use the default if no state was found or given
|
||||||
|
if (foundState == null)
|
||||||
|
{
|
||||||
|
if (blockStatePropertiesString != null)
|
||||||
|
{
|
||||||
|
// we should have found a blockstate, but didn't
|
||||||
|
if (!BrokenResourceLocations.contains(resourceLocation))
|
||||||
|
{
|
||||||
|
BrokenResourceLocations.add(resourceLocation);
|
||||||
|
LOGGER.warn("Unable to find BlockState for Block [" + resourceLocation + "] with properties: [" + blockStatePropertiesString + "]. Using the default block state.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foundState = block.defaultBlockState();
|
||||||
|
}
|
||||||
|
|
||||||
|
foundWrapper = new BlockStateWrapper(foundState, levelWrapper);
|
||||||
|
return foundWrapper;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new IOException("Failed to deserialize the string [" + finalResourceStateString + "] into a BlockStateWrapper: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
return new BlockStateWrapper(foundState, levelWrapper);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
finally
|
||||||
{
|
{
|
||||||
throw new IOException("Failed to deserialize the string [" + resourceStateString + "] into a BlockStateWrapper: " + e.getMessage(), e);
|
// put if absent in case two threads deserialize at the same time
|
||||||
|
// unfortunately we can't put everything in a computeIfAbsent() since we also throw exceptions
|
||||||
|
WRAPPER_BY_RESOURCE_LOCATION.putIfAbsent(finalResourceStateString, foundWrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -487,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")
|
||||||
@@ -504,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
|
||||||
@@ -516,18 +699,21 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return IrisBlockMaterial.METAL;
|
return EDhApiBlockMaterial.METAL;
|
||||||
|
}
|
||||||
|
else if (serialString.contains("grass_block"))
|
||||||
|
{
|
||||||
|
return EDhApiBlockMaterial.GRASS;
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
serialString.contains("dirt")
|
serialString.contains("dirt")
|
||||||
|| serialString.contains("grass_block")
|
|
||||||
|| serialString.contains("gravel")
|
|| serialString.contains("gravel")
|
||||||
|| serialString.contains("mud")
|
|| serialString.contains("mud")
|
||||||
|| serialString.contains("podzol")
|
|| serialString.contains("podzol")
|
||||||
|| 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
|
||||||
@@ -536,38 +722,38 @@ 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+60
-12
@@ -19,14 +19,20 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.block;
|
package com.seibel.distanthorizons.common.wrappers.block;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.level.*;
|
import net.minecraft.world.level.*;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
import net.minecraft.world.level.biome.Biomes;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||||
import net.minecraft.world.level.material.FluidState;
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
@@ -35,18 +41,54 @@ import net.minecraft.core.Holder;
|
|||||||
|
|
||||||
public class TintWithoutLevelOverrider implements BlockAndTintGetter
|
public class TintWithoutLevelOverrider implements BlockAndTintGetter
|
||||||
{
|
{
|
||||||
final BiomeWrapper biome;
|
/**
|
||||||
|
* This will only ever be null if there was an issue with {@link IClientLevelWrapper#getPlainsBiomeWrapper()}
|
||||||
|
* but {@link Nullable} is there just in case.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private final Biome biome;
|
||||||
|
|
||||||
public TintWithoutLevelOverrider(BiomeWrapper biome)
|
|
||||||
|
|
||||||
|
public TintWithoutLevelOverrider(BiomeWrapper biomeWrapper, IClientLevelWrapper clientLevelWrapper)
|
||||||
{
|
{
|
||||||
this.biome = biome;
|
// try to get the wrapped biome
|
||||||
|
Biome unwrappedBiome = null;
|
||||||
|
if (biomeWrapper.biome != null)
|
||||||
|
{
|
||||||
|
unwrappedBiome = unwrap(biomeWrapper.biome);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(unwrappedBiome == null)
|
||||||
|
{
|
||||||
|
// we are looking at the empty biome wrapper, try using plains as a backup
|
||||||
|
BiomeWrapper plainsBiomeWrapper = ((BiomeWrapper) clientLevelWrapper.getPlainsBiomeWrapper());
|
||||||
|
if (plainsBiomeWrapper != null)
|
||||||
|
{
|
||||||
|
unwrappedBiome = unwrap(plainsBiomeWrapper.biome);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.biome = unwrappedBiome;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver)
|
||||||
{
|
{
|
||||||
return colorResolver.getColor(_unwrap(biome.biome), blockPos.getX(), blockPos.getZ());
|
if (this.biome != null)
|
||||||
|
{
|
||||||
|
return colorResolver.getColor(this.biome, blockPos.getX(), blockPos.getZ());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// hopefully unneeded debug color
|
||||||
|
return ColorUtil.CYAN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private Biome _unwrap(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
|
|
||||||
|
private static Biome unwrap(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
|
||||||
{
|
{
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
return biome.value();
|
return biome.value();
|
||||||
@@ -55,30 +97,36 @@ public class TintWithoutLevelOverrider implements BlockAndTintGetter
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// unused methods //
|
||||||
|
//================//
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getShade(Direction direction, boolean shade)
|
public float getShade(@NotNull Direction direction, boolean shade)
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public LevelLightEngine getLightEngine()
|
public @NotNull LevelLightEngine getLightEngine()
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||||
}
|
}
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BlockEntity getBlockEntity(BlockPos pos)
|
public BlockEntity getBlockEntity(@NotNull BlockPos pos)
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState getBlockState(BlockPos pos)
|
public @NotNull BlockState getBlockState(@NotNull BlockPos pos)
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public FluidState getFluidState(BlockPos pos)
|
public @NotNull FluidState getFluidState(@NotNull BlockPos pos)
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||||
}
|
}
|
||||||
|
|||||||
-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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-316
@@ -1,316 +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 BlockState blockState;
|
|
||||||
public final LevelReader level;
|
|
||||||
public final BlockPos pos;
|
|
||||||
public ClientBlockStateCache(BlockState blockState, IClientLevelWrapper samplingLevel, DhBlockPos samplingPos)
|
|
||||||
{
|
|
||||||
this.blockState = blockState;
|
|
||||||
level = (LevelReader) samplingLevel.getWrappedMcObject();
|
|
||||||
pos = McObjectConverter.Convert(samplingPos);
|
|
||||||
resolveColors();
|
|
||||||
//LOGGER.info("ClientBlocKCache created for {}", blockState);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isColorResolved = false;
|
|
||||||
int baseColor = 0; //TODO: Impl per-face color
|
|
||||||
boolean needShade = true;
|
|
||||||
boolean needPostTinting = false;
|
|
||||||
int tintIndex = 0;
|
|
||||||
|
|
||||||
|
|
||||||
public static final int FLOWER_COLOR_SCALE = 5;
|
|
||||||
|
|
||||||
enum ColorMode
|
|
||||||
{
|
|
||||||
Default,
|
|
||||||
Flower,
|
|
||||||
Leaves,
|
|
||||||
Chisel;
|
|
||||||
static ColorMode getColorMode(Block b)
|
|
||||||
{
|
|
||||||
if (b instanceof LeavesBlock) return Leaves;
|
|
||||||
if (b instanceof FlowerBlock) return Flower;
|
|
||||||
if (b.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel;
|
|
||||||
return Default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
double alpha = 0;
|
|
||||||
double red = 0;
|
|
||||||
double green = 0;
|
|
||||||
double blue = 0;
|
|
||||||
int tempColor;
|
|
||||||
{
|
|
||||||
// textures normally use u and v instead of x and y
|
|
||||||
for (int u = 0; u < getWidth(texture); u++)
|
|
||||||
{
|
|
||||||
for (int v = 0; v < getHeight(texture); v++)
|
|
||||||
{
|
|
||||||
//note: Minecraft color format is: 0xAA BB GG RR
|
|
||||||
//________ DH mod color format is: 0xAA RR GG BB
|
|
||||||
//OpenGL RGBA format native order: 0xRR GG BB AA
|
|
||||||
//_ OpenGL RGBA format Java Order: 0xAA BB GG RR
|
|
||||||
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
|
|
||||||
|
|
||||||
double r = ((tempColor & 0x000000FF)) / 255.;
|
|
||||||
double g = ((tempColor & 0x0000FF00) >>> 8) / 255.;
|
|
||||||
double b = ((tempColor & 0x00FF0000) >>> 16) / 255.;
|
|
||||||
double a = ((tempColor & 0xFF000000) >>> 24) / 255.;
|
|
||||||
int scale = 1;
|
|
||||||
|
|
||||||
if (colorMode == ColorMode.Leaves)
|
|
||||||
{
|
|
||||||
r *= a;
|
|
||||||
g *= a;
|
|
||||||
b *= a;
|
|
||||||
a = 1.;
|
|
||||||
}
|
|
||||||
else if (a == 0.)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (colorMode == ColorMode.Flower && (g + 0.1 < b || g + 0.1 < r))
|
|
||||||
{
|
|
||||||
scale = FLOWER_COLOR_SCALE;
|
|
||||||
}
|
|
||||||
//make Chiseled block not render
|
|
||||||
else if (colorMode == ColorMode.Chisel)
|
|
||||||
{
|
|
||||||
r = 0;
|
|
||||||
g = 0;
|
|
||||||
b = 0;
|
|
||||||
a = 0;
|
|
||||||
}
|
|
||||||
count += scale;
|
|
||||||
alpha += a * a * scale;
|
|
||||||
red += r * r * scale;
|
|
||||||
green += g * g * scale;
|
|
||||||
blue += b * b * scale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 0)
|
|
||||||
// this block is entirely transparent
|
|
||||||
tempColor = ColorUtil.rgbToInt(0, 255, 255, 255);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// determine the average color
|
|
||||||
tempColor = ColorUtil.rgbToInt(
|
|
||||||
(int) (Math.sqrt(alpha / count) * 255.),
|
|
||||||
(int) (Math.sqrt(red / count) * 255.),
|
|
||||||
(int) (Math.sqrt(green / count) * 255.),
|
|
||||||
(int) (Math.sqrt(blue / count) * 255.));
|
|
||||||
}
|
|
||||||
return tempColor;
|
|
||||||
}
|
|
||||||
private static final Direction[] DIRECTION_ORDER = {Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN};
|
|
||||||
|
|
||||||
private void resolveColors()
|
|
||||||
{
|
|
||||||
if (isColorResolved) return;
|
|
||||||
if (blockState.getFluidState().isEmpty())
|
|
||||||
{
|
|
||||||
List<BakedQuad> quads = null;
|
|
||||||
for (Direction direction : DIRECTION_ORDER)
|
|
||||||
{
|
|
||||||
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
|
||||||
getBlockModel(blockState).getQuads(blockState, direction, random);
|
|
||||||
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), 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-216
@@ -1,216 +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;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public ChunkLightStorage(int minY, int maxY)
|
|
||||||
{
|
|
||||||
this.minY = minY;
|
|
||||||
this.maxY = maxY;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public int get(int x, int y, int z)
|
|
||||||
{
|
|
||||||
if (y < this.minY)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (y >= this.maxY)
|
|
||||||
{
|
|
||||||
return 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
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); }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+119
-132
@@ -22,23 +22,24 @@ 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;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
import net.minecraft.world.level.LightLayer;
|
import net.minecraft.world.level.LightLayer;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
|
|
||||||
@@ -73,13 +74,17 @@ import net.minecraft.world.level.lighting.LevelLightEngine;
|
|||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public class ChunkWrapper implements IChunkWrapper
|
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());
|
||||||
|
|
||||||
@@ -103,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).
|
||||||
@@ -136,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()
|
||||||
@@ -215,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;
|
||||||
@@ -222,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,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
|
||||||
@@ -257,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)
|
||||||
{
|
{
|
||||||
@@ -281,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
|
||||||
@@ -295,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; }
|
||||||
@@ -304,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()
|
||||||
{
|
{
|
||||||
@@ -321,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;
|
||||||
@@ -358,10 +389,13 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
{
|
{
|
||||||
if (this.blockLightStorage == null)
|
if (this.blockLightStorage == null)
|
||||||
{
|
{
|
||||||
this.blockLightStorage = new ChunkLightStorage(this.getMinBuildHeight(), this.getMaxBuildHeight());
|
this.blockLightStorage = ChunkLightStorage.createBlockLightStorage(this);
|
||||||
}
|
}
|
||||||
return this.blockLightStorage;
|
return this.blockLightStorage;
|
||||||
}
|
}
|
||||||
|
public void setBlockLightStorage(ChunkLightStorage lightStorage) { this.blockLightStorage = lightStorage; }
|
||||||
|
@Override
|
||||||
|
public void clearDhBlockLighting() { this.getBlockLightStorage().clear(); }
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -376,15 +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.getMinBuildHeight(), this.getMaxBuildHeight());
|
this.skyLightStorage = ChunkLightStorage.createSkyLightStorage(this);
|
||||||
}
|
}
|
||||||
return this.skyLightStorage;
|
return this.skyLightStorage;
|
||||||
}
|
}
|
||||||
|
public void setSkyLightStorage(ChunkLightStorage lightStorage) { this.skyLightStorage = lightStorage; }
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -430,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)
|
||||||
@@ -446,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
|
||||||
}
|
}
|
||||||
@@ -454,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
|
||||||
@@ -562,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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
return true;
|
||||||
final int yRel = y + this.getMinBuildHeight();
|
|
||||||
|
|
||||||
final int xRel = index % LodUtil.CHUNK_WIDTH;
|
|
||||||
return new DhBlockPos(xRel, yRel, zRel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; }
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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;
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
+40
-20
@@ -16,7 +16,7 @@ import java.util.regex.Pattern;
|
|||||||
// Logger (for debug stuff)
|
// Logger (for debug stuff)
|
||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui;
|
import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui;
|
||||||
import com.seibel.distanthorizons.api.enums.config.EUpdateBranch;
|
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
|
||||||
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.types.*;
|
import com.seibel.distanthorizons.core.config.types.*;
|
||||||
@@ -98,6 +98,7 @@ public class ClassicConfigGUI
|
|||||||
public static final int SpaceFromRightScreen = 10;
|
public static final int SpaceFromRightScreen = 10;
|
||||||
public static final int ButtonWidthSpacing = 5;
|
public static final int ButtonWidthSpacing = 5;
|
||||||
public static final int ResetButtonWidth = 40;
|
public static final int ResetButtonWidth = 40;
|
||||||
|
public static final int ResetButtonHeight = 20;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,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;
|
||||||
};
|
};
|
||||||
@@ -244,17 +248,23 @@ public class ClassicConfigGUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Changelog button
|
// Changelog button
|
||||||
if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() && Config.Client.Advanced.AutoUpdater.updateBranch.get() == EUpdateBranch.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
|
||||||
this.width - 28, this.height - 28,
|
this.width - 28, this.height - 28,
|
||||||
// Width and height of the button
|
// Width and height of the button
|
||||||
20, 20,
|
20, 20,
|
||||||
// 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);
|
||||||
@@ -269,18 +279,25 @@ public class ClassicConfigGUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
addBtn(MakeBtn(Translatable("distanthorizons.general.cancel"), this.width / 2 - 154, this.height - 28, 150, 20, button -> {
|
addBtn(MakeBtn(Translatable("distanthorizons.general.cancel"),
|
||||||
ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile();
|
this.width / 2 - 154, this.height - 28,
|
||||||
Objects.requireNonNull(minecraft).setScreen(parent);
|
150, 20,
|
||||||
}));
|
button ->
|
||||||
|
{
|
||||||
|
ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile();
|
||||||
|
Objects.requireNonNull(minecraft).setScreen(parent);
|
||||||
|
}));
|
||||||
doneButton = addBtn(MakeBtn(Translatable("distanthorizons.general.done"), this.width / 2 + 4, this.height - 28, 150, 20, (button) -> {
|
doneButton = addBtn(MakeBtn(Translatable("distanthorizons.general.done"), this.width / 2 + 4, this.height - 28, 150, 20, (button) -> {
|
||||||
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
|
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
|
||||||
Objects.requireNonNull(minecraft).setScreen(parent);
|
Objects.requireNonNull(minecraft).setScreen(parent);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.list = new ConfigListWidget(this.minecraft, this.width * 2, this.height, 32, 32, 25);
|
this.list = new ConfigListWidget(this.minecraft, this.width * 2, this.height, 32, 32, 25);
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
|
||||||
if (this.minecraft != null && this.minecraft.level != null)
|
if (this.minecraft != null && this.minecraft.level != null)
|
||||||
this.list.setRenderBackground(false);
|
this.list.setRenderBackground(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
this.addWidget(this.list);
|
this.addWidget(this.list);
|
||||||
|
|
||||||
@@ -311,6 +328,7 @@ public class ClassicConfigGUI
|
|||||||
initEntry(info, this.translationPrefix);
|
initEntry(info, this.translationPrefix);
|
||||||
Component name = Translatable(translationPrefix + info.getNameWCategory());
|
Component name = Translatable(translationPrefix + info.getNameWCategory());
|
||||||
|
|
||||||
|
|
||||||
if (ConfigEntry.class.isAssignableFrom(info.getClass()))
|
if (ConfigEntry.class.isAssignableFrom(info.getClass()))
|
||||||
{
|
{
|
||||||
Button.OnPress btnAction = button -> {
|
Button.OnPress btnAction = button -> {
|
||||||
@@ -319,12 +337,12 @@ public class ClassicConfigGUI
|
|||||||
this.reload = true;
|
this.reload = true;
|
||||||
Objects.requireNonNull(minecraft).setScreen(this);
|
Objects.requireNonNull(minecraft).setScreen(this);
|
||||||
};
|
};
|
||||||
int a = this.width - ConfigScreenConfigs.SpaceFromRightScreen - 150 - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth;
|
int posX = this.width - ConfigScreenConfigs.SpaceFromRightScreen - 150 - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth;
|
||||||
int b = 0;
|
int posZ = 0;
|
||||||
int c = ConfigScreenConfigs.ResetButtonWidth;
|
|
||||||
int d = 20;
|
|
||||||
|
|
||||||
Button resetButton = MakeBtn(Translatable("distanthorizons.general.reset").withStyle(ChatFormatting.RED), a, b, c, d, btnAction);
|
Button resetButton = MakeBtn(Translatable("distanthorizons.general.reset").withStyle(ChatFormatting.RED),
|
||||||
|
posX, posZ, ConfigScreenConfigs.ResetButtonWidth, ConfigScreenConfigs.ResetButtonHeight,
|
||||||
|
btnAction);
|
||||||
|
|
||||||
if (((EntryInfo) info.guiValue).widget instanceof Map.Entry)
|
if (((EntryInfo) info.guiValue).widget instanceof Map.Entry)
|
||||||
{
|
{
|
||||||
@@ -428,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<>();
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ public class GetConfigScreen
|
|||||||
case JavaFX:
|
case JavaFX:
|
||||||
return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new ConfigScreen()), ModInfo.ID + ".title");
|
return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new ConfigScreen()), ModInfo.ID + ".title");
|
||||||
default:
|
default:
|
||||||
return null;
|
throw new IllegalArgumentException("No config screen implementation defined for ["+useScreen+"].");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ public class GuiHelper
|
|||||||
/**
|
/**
|
||||||
* Helper static methods for versional compat
|
* Helper static methods for versional compat
|
||||||
*/
|
*/
|
||||||
public static Button MakeBtn(Component base, int a, int b, int c, int d, Button.OnPress action)
|
public static Button MakeBtn(Component base, int posX, int posZ, int width, int height, Button.OnPress action)
|
||||||
{
|
{
|
||||||
#if MC_VER < MC_1_19_4
|
#if MC_VER < MC_1_19_4
|
||||||
return new Button(a, b, c, d, base, action);
|
return new Button(posX, posZ, width, height, base, action);
|
||||||
#else
|
#else
|
||||||
return Button.builder(base, action).bounds(a, b, c, d).build();
|
return Button.builder(base, action).bounds(posX, posZ, width, height).build();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
@@ -60,8 +60,12 @@ public class MinecraftScreen
|
|||||||
screen.init(); // Init our own config screen
|
screen.init(); // Init our own config screen
|
||||||
|
|
||||||
this.list = new ConfigListWidget(this.minecraft, this.width, this.height, 0, 0, 25); // Select the area to tint
|
this.list = new ConfigListWidget(this.minecraft, this.width, this.height, 0, 0, 25); // Select the area to tint
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
|
||||||
if (this.minecraft != null && this.minecraft.level != null) // Check if in game
|
if (this.minecraft != null && this.minecraft.level != null) // Check if in game
|
||||||
this.list.setRenderBackground(false); // Disable from rendering
|
this.list.setRenderBackground(false); // Disable from rendering
|
||||||
|
#endif
|
||||||
|
|
||||||
this.addWidget(this.list); // Add the tint to the things to be rendered
|
this.addWidget(this.list); // Add the tint to the things to be rendered
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+31
-23
@@ -1,23 +1,19 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers.gui.updater;
|
package com.seibel.distanthorizons.common.wrappers.gui.updater;
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.NativeImage;
|
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
|
||||||
import com.seibel.distanthorizons.api.enums.config.EUpdateBranch;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.gui.DhScreen;
|
import com.seibel.distanthorizons.common.wrappers.gui.DhScreen;
|
||||||
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
|
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
|
||||||
import com.seibel.distanthorizons.core.jar.ModJarInfo;
|
import com.seibel.distanthorizons.core.jar.ModJarInfo;
|
||||||
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 com.seibel.distanthorizons.core.jar.JarUtils;
|
|
||||||
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 net.minecraft.client.Minecraft;
|
|
||||||
#if MC_VER >= MC_1_20_1
|
#if MC_VER >= MC_1_20_1
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
#else
|
#else
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
#endif
|
#endif
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
|
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
|
||||||
@@ -45,16 +41,18 @@ public class UpdateModScreen extends DhScreen
|
|||||||
super(Translatable(ModInfo.ID + ".updater.title"));
|
super(Translatable(ModInfo.ID + ".updater.title"));
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,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)
|
||||||
@@ -92,7 +96,7 @@ public class UpdateModScreen extends DhScreen
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EUpdateBranch.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
|
||||||
@@ -102,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
|
||||||
@@ -151,17 +161,15 @@ public class UpdateModScreen extends DhScreen
|
|||||||
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
|
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// TODO: add the tooltips for the buttons
|
||||||
|
super.render(matrices, mouseX, mouseY, delta); // Render the buttons
|
||||||
|
// TODO: Add tooltips
|
||||||
|
|
||||||
// Render the text's
|
// Render the text's
|
||||||
DhDrawCenteredString(matrices, this.font, Translatable(ModInfo.ID + ".updater.text1"), this.width / 2, this.height / 2 - 35, 0xFFFFFF);
|
DhDrawCenteredString(matrices, this.font, Translatable(ModInfo.ID + ".updater.text1"), this.width / 2, this.height / 2 - 35, 0xFFFFFF);
|
||||||
DhDrawCenteredString(matrices, this.font,
|
DhDrawCenteredString(matrices, this.font,
|
||||||
Translatable(ModInfo.ID + ".updater.text2", currentVer, nextVer),
|
Translatable(ModInfo.ID + ".updater.text2", currentVer, nextVer),
|
||||||
this.width / 2, this.height / 2 - 20, 0x52FD52);
|
this.width / 2, this.height / 2 - 20, 0x52FD52);
|
||||||
|
|
||||||
// TODO: add the tooltips for the buttons
|
|
||||||
super.render(matrices, mouseX, mouseY, delta); // Render the buttons
|
|
||||||
|
|
||||||
// TODO: Add tooltips
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+89
-74
@@ -25,12 +25,13 @@ import java.util.ArrayList;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.NativeImage;
|
import com.mojang.blaze3d.platform.NativeImage;
|
||||||
import com.seibel.distanthorizons.api.enums.config.ELodShading;
|
import com.seibel.distanthorizons.api.enums.config.EDhApiLodShading;
|
||||||
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.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -113,22 +112,22 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
|||||||
@Override
|
@Override
|
||||||
public float getShade(EDhDirection lodDirection)
|
public float getShade(EDhDirection lodDirection)
|
||||||
{
|
{
|
||||||
ELodShading lodShading = Config.Client.Advanced.Graphics.AdvancedGraphics.lodShading.get();
|
EDhApiLodShading lodShading = Config.Client.Advanced.Graphics.AdvancedGraphics.lodShading.get();
|
||||||
switch (lodShading)
|
switch (lodShading)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case MINECRAFT:
|
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
|
||||||
{
|
{
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OLD_LIGHTING:
|
case ENABLED:
|
||||||
switch (lodDirection)
|
switch (lodDirection)
|
||||||
{
|
{
|
||||||
case DOWN:
|
case DOWN:
|
||||||
@@ -144,53 +143,69 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
|||||||
return 0.6F;
|
return 0.6F;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NONE:
|
case DISABLED:
|
||||||
return 1.0F;
|
return 1.0F;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-7
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+24
-146
@@ -21,30 +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.concurrent.ConcurrentHashMap;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
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;
|
||||||
@@ -54,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;
|
||||||
@@ -77,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;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,7 +93,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
|||||||
* In the case of immersive portals multiple levels may be active at once, causing conflicting lightmaps. <br>
|
* In the case of immersive portals multiple levels may be active at once, causing conflicting lightmaps. <br>
|
||||||
* Requiring the use of multiple {@link LightMapWrapper}.
|
* Requiring the use of multiple {@link LightMapWrapper}.
|
||||||
*/
|
*/
|
||||||
public HashMap<IDimensionTypeWrapper, LightMapWrapper> lightmapByDimensionType = new HashMap<>();
|
public ConcurrentHashMap<IDimensionTypeWrapper, LightMapWrapper> lightmapByDimensionType = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the render buffer that should be used when displaying levels to the screen.
|
* Holds the render buffer that should be used when displaying levels to the screen.
|
||||||
@@ -122,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()
|
||||||
@@ -150,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)
|
||||||
{
|
{
|
||||||
@@ -211,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
|
||||||
@@ -307,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()); }
|
||||||
|
|
||||||
@@ -405,11 +286,8 @@ 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();
|
||||||
|
|
||||||
if (!this.lightmapByDimensionType.containsKey(dimensionType))
|
LightMapWrapper wrapper = this.lightmapByDimensionType.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper());
|
||||||
{
|
wrapper.uploadLightmap(lightPixels);
|
||||||
this.lightmapByDimensionType.put(dimensionType, new LightMapWrapper());
|
|
||||||
}
|
|
||||||
this.lightmapByDimensionType.get(dimensionType).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()
|
||||||
|
|||||||
+82
-16
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+149
-37
@@ -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,27 +19,42 @@ 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.level.chunk.ChunkStatus;
|
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.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#endif
|
||||||
|
|
||||||
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 BiomeWrapper plainsBiomeWrapper;
|
||||||
|
@Deprecated // TODO circular references are bad
|
||||||
|
private IDhLevel parentDhLevel;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -55,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
|
||||||
@@ -79,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
|
||||||
@@ -99,25 +122,77 @@ 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
|
||||||
|
public int getDirtBlockColor()
|
||||||
|
{
|
||||||
|
if (this.dirtBlockWrapper == null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.dirtBlockWrapper = (BlockStateWrapper) BlockStateWrapper.deserialize(BlockStateWrapper.DIRT_RESOURCE_LOCATION_STRING, this);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
// shouldn't happen, but just in case
|
||||||
|
LOGGER.warn("Unable to get dirt color with resource location ["+BlockStateWrapper.DIRT_RESOURCE_LOCATION_STRING+"] with level ["+this+"].", e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getBlockColor(DhBlockPos.ZERO,BiomeWrapper.EMPTY_WRAPPER, this.dirtBlockWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearBlockColorCache() { this.blockCache.clear(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBiomeWrapper getPlainsBiomeWrapper()
|
||||||
|
{
|
||||||
|
if (this.plainsBiomeWrapper == null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.plainsBiomeWrapper = (BiomeWrapper) BiomeWrapper.deserialize(BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING, this);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
// shouldn't happen, but just in case
|
||||||
|
LOGGER.warn("Unable to get planes biome with resource location ["+BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING+"] with level ["+this+"].", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.plainsBiomeWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@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; }
|
||||||
@@ -131,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()
|
||||||
@@ -146,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;
|
||||||
@@ -180,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()
|
||||||
@@ -190,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() + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+21
-7
@@ -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)
|
||||||
@@ -102,4 +116,4 @@ public class DimensionTypeWrapper implements IDimensionTypeWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+61
-42
@@ -23,28 +23,31 @@ 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;
|
||||||
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;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#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
|
||||||
@@ -54,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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -76,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
|
||||||
@@ -106,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
|
||||||
@@ -133,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() + "}"; }
|
||||||
|
|
||||||
|
}
|
||||||
+317
-186
@@ -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;
|
||||||
@@ -66,7 +67,6 @@ import net.minecraft.server.level.ServerLevel;
|
|||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
import net.minecraft.world.level.chunk.UpgradeData;
|
import net.minecraft.world.level.chunk.UpgradeData;
|
||||||
@@ -79,6 +79,12 @@ import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
|||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Total: 3.135214124s
|
Total: 3.135214124s
|
||||||
=====================================
|
=====================================
|
||||||
@@ -104,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 = {
|
||||||
@@ -220,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
|
||||||
{
|
{
|
||||||
@@ -249,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)
|
||||||
@@ -289,6 +298,9 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=================//
|
||||||
|
// synchronization //
|
||||||
|
//=================//
|
||||||
|
|
||||||
public <T> T joinSync(CompletableFuture<T> future)
|
public <T> T joinSync(CompletableFuture<T> future)
|
||||||
{
|
{
|
||||||
@@ -339,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())
|
||||||
@@ -363,31 +378,251 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProtoChunk EmptyChunk(ServerLevel level, ChunkPos chunkPos)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChunkAccess loadOrMakeChunk(ChunkPos chunkPos)
|
|
||||||
|
//==================//
|
||||||
|
// world generation //
|
||||||
|
//==================//
|
||||||
|
|
||||||
|
public void generateLodFromList(GenerationEvent genEvent) throws InterruptedException
|
||||||
|
{
|
||||||
|
EVENT_LOGGER.debug("Lod Generate Event: " + genEvent.minPos);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
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
|
||||||
{
|
{
|
||||||
@@ -420,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,
|
||||||
@@ -689,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);
|
||||||
}
|
}
|
||||||
@@ -710,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(); }
|
||||||
@@ -771,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
|
||||||
@@ -784,4 +903,16 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper classes //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface IEmptyChunkGeneratorFunc
|
||||||
|
{
|
||||||
|
ChunkAccess generate(int x, int z);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+8
-26
@@ -26,13 +26,11 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
||||||
import com.seibel.distanthorizons.core.generation.WorldGenerationQueue;
|
|
||||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
|
||||||
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
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.threading.ThreadPools;
|
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 org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@@ -45,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;
|
||||||
@@ -75,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);
|
||||||
@@ -95,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();
|
||||||
@@ -123,26 +120,11 @@ public final class GenerationEvent
|
|||||||
public boolean terminate()
|
public boolean terminate()
|
||||||
{
|
{
|
||||||
LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN=======================");
|
LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN=======================");
|
||||||
ThreadPools.WORLD_GEN_THREAD_FACTORY.dumpAllThreadStacks();
|
ThreadPoolUtil.WORLD_GEN_THREAD_FACTORY.dumpAllThreadStacks();
|
||||||
this.future.cancel(true);
|
this.future.cancel(true);
|
||||||
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();
|
||||||
|
|||||||
+324
-139
@@ -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.*;
|
||||||
@@ -76,6 +82,14 @@ import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
|||||||
import net.minecraft.world.level.material.Fluids;
|
import net.minecraft.world.level.material.Fluids;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER == MC_1_20_6
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
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
|
||||||
|
|
||||||
import net.minecraft.world.level.material.Fluid;
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
|
||||||
|
|
||||||
@@ -95,133 +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)
|
|
||||||
{
|
|
||||||
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)).getOrThrow(false, LOGGER::error)
|
|
||||||
: 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)).getOrThrow(false, LOGGER::error)
|
|
||||||
: 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)
|
//============//
|
||||||
{
|
// read chunk //
|
||||||
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 ChunkStatus.ChunkType readChunkType(CompoundTag tagLevel)
|
|
||||||
{
|
|
||||||
ChunkStatus chunkStatus = ChunkStatus.byName(tagLevel.getString("Status"));
|
|
||||||
if (chunkStatus != null)
|
|
||||||
{
|
|
||||||
return chunkStatus.getChunkType();
|
|
||||||
}
|
|
||||||
return ChunkStatus.ChunkType.PROTOCHUNK;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LevelChunk read(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData)
|
public static LevelChunk read(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData)
|
||||||
{
|
{
|
||||||
@@ -234,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))
|
||||||
@@ -262,19 +156,27 @@ public class ChunkLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ChunkStatus.ChunkType chunkType = readChunkType(tagLevel);
|
#if MC_VER < MC_1_20_6
|
||||||
#if MC_VER < MC_1_18_2
|
ChunkStatus.ChunkType chunkType;
|
||||||
if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK)
|
|
||||||
return null;
|
|
||||||
#else
|
#else
|
||||||
BlendingData blendingData = readBlendingData(tagLevel);
|
ChunkType chunkType;
|
||||||
#if MC_VER < MC_1_19_2
|
|
||||||
if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || !blendingData.oldNoise()))
|
|
||||||
return null;
|
|
||||||
#else
|
|
||||||
if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && blendingData == null)
|
|
||||||
return null;
|
|
||||||
#endif
|
#endif
|
||||||
|
chunkType = readChunkType(tagLevel);
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK)
|
||||||
|
return null;
|
||||||
|
#else
|
||||||
|
|
||||||
|
BlendingData blendingData = readBlendingData(tagLevel);
|
||||||
|
#if MC_VER < MC_1_19_2
|
||||||
|
if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || !blendingData.oldNoise()))
|
||||||
|
return null;
|
||||||
|
#else
|
||||||
|
if (chunkType == #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType.PROTOCHUNK #else ChunkType.PROTOCHUNK #endif && blendingData == null)
|
||||||
|
return null;
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
long inhabitedTime = tagLevel.getLong("InhabitedTime");
|
long inhabitedTime = tagLevel.getLong("InhabitedTime");
|
||||||
@@ -331,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
|
||||||
+132
-62
@@ -22,12 +22,14 @@ 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 net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import net.minecraft.world.level.block.SpawnerBlock;
|
import net.minecraft.world.level.block.SpawnerBlock;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
@@ -50,28 +52,44 @@ import net.minecraft.world.level.block.Blocks;
|
|||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
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.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
public class DhLitWorldGenRegion extends WorldGenRegion
|
public class DhLitWorldGenRegion extends WorldGenRegion
|
||||||
{
|
{
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||||
|
|
||||||
|
private static ChunkStatus debugTriggeredForStatus = null;
|
||||||
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
private final ChunkPos firstPos;
|
private final ChunkPos firstPos;
|
||||||
private final List<ChunkAccess> cache;
|
private final List<ChunkAccess> cache;
|
||||||
Long2ObjectOpenHashMap<ChunkAccess> chunkMap = new Long2ObjectOpenHashMap<ChunkAccess>();
|
private final Long2ObjectOpenHashMap<ChunkAccess> chunkMap = new Long2ObjectOpenHashMap<ChunkAccess>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Present to reduce the chance that we accidentally break underlying MC code that isn't thread safe,
|
* Present to reduce the chance that we accidentally break underlying MC code that isn't thread safe,
|
||||||
* specifically: "it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap.getAndMoveToFirst()"
|
* specifically: "it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap.getAndMoveToFirst()"
|
||||||
*/
|
*/
|
||||||
ReentrantLock getChunkLock = new ReentrantLock();
|
private final ReentrantLock getChunkLock = new ReentrantLock();
|
||||||
|
|
||||||
#if MC_VER < MC_1_18_2
|
#if MC_VER < MC_1_18_2
|
||||||
private ChunkPos overrideCenterPos = null;
|
private ChunkPos overrideCenterPos = null;
|
||||||
@@ -100,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;
|
||||||
@@ -198,13 +234,26 @@ public class DhLitWorldGenRegion extends WorldGenRegion
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip BlockEntity stuff. It aren't really needed
|
/**
|
||||||
|
* 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
|
@Override
|
||||||
public boolean addFreshEntity(Entity entity)
|
public BlockState getBlockState(BlockPos blockPos)
|
||||||
{
|
{
|
||||||
return true;
|
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. */
|
||||||
|
@Override
|
||||||
|
public boolean addFreshEntity(@NotNull Entity entity) { return true; }
|
||||||
|
|
||||||
// Allays have empty chunks even if it's outside the worldGenRegion
|
// Allays have empty chunks even if it's outside the worldGenRegion
|
||||||
// @Override
|
// @Override
|
||||||
// public boolean hasChunk(int i, int j) {
|
// public boolean hasChunk(int i, int j) {
|
||||||
@@ -214,13 +263,13 @@ public class DhLitWorldGenRegion extends WorldGenRegion
|
|||||||
// Override to ensure no other mod mixins cause skipping the overrided
|
// Override to ensure no other mod mixins cause skipping the overrided
|
||||||
// getChunk(...)
|
// getChunk(...)
|
||||||
@Override
|
@Override
|
||||||
public ChunkAccess getChunk(int i, int j)
|
public @NotNull ChunkAccess getChunk(int chunkX, int chunkZ)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// lock is to prevent issues with underlying MC code that doesn't support multithreading
|
// lock is to prevent issues with underlying MC code that doesn't support multithreading
|
||||||
this.getChunkLock.lock();
|
this.getChunkLock.lock();
|
||||||
return this.getChunk(i, j, ChunkStatus.EMPTY);
|
return this.getChunk(chunkX, chunkZ, ChunkStatus.EMPTY);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -231,13 +280,19 @@ public class DhLitWorldGenRegion extends WorldGenRegion
|
|||||||
// Override to ensure no other mod mixins cause skipping the overrided
|
// Override to ensure no other mod mixins cause skipping the overrided
|
||||||
// getChunk(...)
|
// getChunk(...)
|
||||||
@Override
|
@Override
|
||||||
public ChunkAccess getChunk(int i, int j, ChunkStatus chunkStatus)
|
public @NotNull ChunkAccess getChunk(int chunkX, int chunkZ, @NotNull ChunkStatus chunkStatus)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// lock is to prevent issues with underlying MC code that doesn't support multithreading
|
// lock is to prevent issues with underlying MC code that doesn't support multithreading
|
||||||
this.getChunkLock.lock();
|
this.getChunkLock.lock();
|
||||||
return this.getChunk(i, j, chunkStatus, true);
|
|
||||||
|
ChunkAccess chunk = this.getChunk(chunkX, chunkZ, chunkStatus, true);
|
||||||
|
if (chunk == null)
|
||||||
|
{
|
||||||
|
LodUtil.assertNotReach("getChunk shouldn't return null values");
|
||||||
|
}
|
||||||
|
return chunk;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -245,28 +300,12 @@ public class DhLitWorldGenRegion extends WorldGenRegion
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use this instead of super.getChunk() to bypass C2ME concurrency checks
|
/** Allows creating empty chunks even if they're outside the worldGenRegion */
|
||||||
private ChunkAccess superGetChunk(int x, int z, ChunkStatus cs)
|
|
||||||
{
|
|
||||||
int k = x - firstPos.x;
|
|
||||||
int l = z - firstPos.z;
|
|
||||||
return cache.get(k + l * size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use this instead of super.hasChunk() to bypass C2ME concurrency checks
|
|
||||||
public boolean superHasChunk(int x, int z)
|
|
||||||
{
|
|
||||||
int k = x - firstPos.x;
|
|
||||||
int l = z - firstPos.z;
|
|
||||||
return l >= 0 && l < size && k >= 0 && k < size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow creating empty chunks even if it's outside the worldGenRegion
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public ChunkAccess getChunk(int i, int j, ChunkStatus chunkStatus, boolean bl)
|
public ChunkAccess getChunk(int chunkX, int chunkZ, @NotNull ChunkStatus chunkStatus, boolean returnNonNull)
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = getChunkAccess(i, j, chunkStatus, bl);
|
ChunkAccess chunk = this.getChunkAccess(chunkX, chunkZ, chunkStatus, returnNonNull);
|
||||||
if (chunk instanceof LevelChunk)
|
if (chunk instanceof LevelChunk)
|
||||||
{
|
{
|
||||||
chunk = new ImposterProtoChunk((LevelChunk) chunk #if MC_VER >= MC_1_18_2 , true #endif );
|
chunk = new ImposterProtoChunk((LevelChunk) chunk #if MC_VER >= MC_1_18_2 , true #endif );
|
||||||
@@ -274,67 +313,98 @@ public class DhLitWorldGenRegion extends WorldGenRegion
|
|||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ChunkStatus debugTriggeredForStatus = null;
|
/**
|
||||||
|
* @param returnNonNull if true this method will always return a non-null chunk,
|
||||||
private ChunkAccess getChunkAccess(int i, int j, ChunkStatus chunkStatus, boolean bl)
|
* if false it will return null if no chunk exists at the given position with the given status
|
||||||
|
*/
|
||||||
|
private ChunkAccess getChunkAccess(int chunkX, int chunkZ, ChunkStatus chunkStatus, boolean returnNonNull)
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = superHasChunk(i, j) ? superGetChunk(i, j, ChunkStatus.EMPTY) : 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;
|
||||||
}
|
}
|
||||||
if (!bl)
|
else if (!returnNonNull)
|
||||||
|
{
|
||||||
|
// no chunk found with the necessary status and null return values are allowed
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// we need a non-null chunk
|
||||||
if (chunk == null)
|
if (chunk == null)
|
||||||
{
|
{
|
||||||
chunk = chunkMap.get(ChunkPos.asLong(i, j));
|
// check memory
|
||||||
|
chunk = this.chunkMap.get(ChunkPos.asLong(chunkX, chunkZ));
|
||||||
if (chunk == null)
|
if (chunk == null)
|
||||||
{
|
{
|
||||||
chunk = generator.generate(i, j);
|
// chunk isn't in memory, generate a new one
|
||||||
|
chunk = this.generator.generate(chunkX, chunkZ);
|
||||||
if (chunk == null)
|
if (chunk == null)
|
||||||
|
{
|
||||||
throw new NullPointerException("The provided generator should not return null!");
|
throw new NullPointerException("The provided generator should not return null!");
|
||||||
chunkMap.put(ChunkPos.asLong(i, j), chunk);
|
}
|
||||||
|
this.chunkMap.put(ChunkPos.asLong(chunkX, chunkZ), chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chunkStatus != ChunkStatus.EMPTY && chunkStatus != debugTriggeredForStatus)
|
if (chunkStatus != ChunkStatus.EMPTY && chunkStatus != debugTriggeredForStatus)
|
||||||
{
|
{
|
||||||
LOGGER.info("WorldGen requiring " + chunkStatus
|
LOGGER.info("WorldGen requiring " + chunkStatus
|
||||||
+ " outside expected range detected. Force passing EMPTY chunk and seeing if it works.");
|
+ " outside expected range detected. Force passing EMPTY chunk and seeing if it works.");
|
||||||
debugTriggeredForStatus = chunkStatus;
|
debugTriggeredForStatus = chunkStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Overriding allows us to use our own lighting engine */
|
/** Use this instead of super.hasChunk() to bypass C2ME concurrency checks */
|
||||||
@Override
|
public boolean superHasChunk(int x, int z)
|
||||||
public LevelLightEngine getLightEngine() { return this.lightEngine; }
|
|
||||||
|
|
||||||
/** Overriding allows us to use our own lighting engine */
|
|
||||||
@Override
|
|
||||||
public int getBrightness(LightLayer lightLayer, BlockPos blockPos) { return 0; }
|
|
||||||
|
|
||||||
/** Overriding allows us to use our own lighting engine */
|
|
||||||
@Override
|
|
||||||
public int getRawBrightness(BlockPos blockPos, int i) { return 0; }
|
|
||||||
|
|
||||||
/** Overriding allows us to use our own lighting engine */
|
|
||||||
@Override
|
|
||||||
public boolean canSeeSky(BlockPos blockPos)
|
|
||||||
{
|
{
|
||||||
return (getBrightness(LightLayer.SKY, blockPos) >= getMaxLightLevel());
|
int k = x - this.firstPos.x;
|
||||||
|
int l = z - this.firstPos.z;
|
||||||
|
return l >= 0 && l < this.size && k >= 0 && k < this.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
/** Use this instead of super.getChunk() to bypass C2ME concurrency checks */
|
||||||
|
private ChunkAccess superGetChunk(int x, int z)
|
||||||
{
|
{
|
||||||
return calculateBlockTint(blockPos, colorResolver);
|
int k = x - this.firstPos.x;
|
||||||
|
int l = z - this.firstPos.z;
|
||||||
|
return this.cache.get(k + l * this.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Overriding allows us to use our own lighting engine */
|
||||||
|
@Override
|
||||||
|
public @NotNull LevelLightEngine getLightEngine() { return this.lightEngine; }
|
||||||
|
|
||||||
|
/** Overriding allows us to use our own lighting engine */
|
||||||
|
@Override
|
||||||
|
public int getBrightness(@NotNull LightLayer lightLayer, @NotNull BlockPos blockPos) { return 0; }
|
||||||
|
|
||||||
|
/** Overriding allows us to use our own lighting engine */
|
||||||
|
@Override
|
||||||
|
public int getRawBrightness(@NotNull BlockPos blockPos, int i) { return 0; }
|
||||||
|
|
||||||
|
/** Overriding allows us to use our own lighting engine */
|
||||||
|
@Override
|
||||||
|
public boolean canSeeSky(@NotNull BlockPos blockPos)
|
||||||
|
{
|
||||||
|
return (this.getBrightness(LightLayer.SKY, blockPos) >= this.getMaxLightLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver)
|
||||||
|
{
|
||||||
|
return this.calculateBlockTint(blockPos, colorResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Biome _getBiome(BlockPos pos)
|
private Biome _getBiome(BlockPos pos)
|
||||||
{
|
{
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
return getBiome(pos).value();
|
return this.getBiome(pos).value();
|
||||||
#else
|
#else
|
||||||
return getBiome(pos);
|
return this.getBiome(pos);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-2
@@ -23,15 +23,24 @@ import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
|
||||||
|
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.chunk.LightChunkGetter;
|
||||||
|
|
||||||
#if MC_VER >= MC_1_17_1
|
#if MC_VER >= MC_1_17_1
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
import net.minecraft.world.level.LevelHeightAccessor;
|
||||||
#endif
|
#endif
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.chunk.LightChunkGetter;
|
|
||||||
#if MC_VER >= MC_1_20_1
|
#if MC_VER >= MC_1_20_1
|
||||||
import net.minecraft.world.level.chunk.LightChunk;
|
import net.minecraft.world.level.chunk.LightChunk;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class LightGetterAdaptor implements LightChunkGetter
|
public class LightGetterAdaptor implements LightChunkGetter
|
||||||
{
|
{
|
||||||
private final BlockGetter heightGetter;
|
private final BlockGetter heightGetter;
|
||||||
|
|||||||
+7
-1
@@ -17,6 +17,10 @@ import java.nio.file.Path;
|
|||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_20_6
|
||||||
|
import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated should be replaced with net.minecraft.world.level.chunk.storage.IOWorker to
|
* @deprecated should be replaced with net.minecraft.world.level.chunk.storage.IOWorker to
|
||||||
* prevent potential file corruption and issues with the C2ME mod.
|
* prevent potential file corruption and issues with the C2ME mod.
|
||||||
@@ -180,8 +184,10 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
|||||||
Path regionFilePath = storageFolderPath.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca");
|
Path regionFilePath = storageFolderPath.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca");
|
||||||
#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
|
||||||
rFile = new RegionFile(regionFilePath.toFile(), storageFolderPath.toFile(), false);
|
rFile = new RegionFile(regionFilePath.toFile(), storageFolderPath.toFile(), false);
|
||||||
#else
|
#elif MC_VER <= MC_1_20_4
|
||||||
rFile = new RegionFile(regionFilePath, storageFolderPath, false);
|
rFile = new RegionFile(regionFilePath, storageFolderPath, false);
|
||||||
|
#else
|
||||||
|
rFile = new RegionFile(new RegionStorageInfo("level", null, "level type"), regionFilePath, storageFolderPath, false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
this.regionFileCache.add(new RegionFileCache(ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ()), rFile));
|
this.regionFileCache.add(new RegionFileCache(ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ()), rFile));
|
||||||
|
|||||||
+6
-1
@@ -35,7 +35,6 @@ import net.minecraft.server.level.WorldGenRegion;
|
|||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.WorldGenLevel;
|
import net.minecraft.world.level.WorldGenLevel;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
||||||
@@ -57,6 +56,12 @@ import net.minecraft.world.level.levelgen.structure.StructureStart;
|
|||||||
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class WorldGenStructFeatManager extends #if MC_VER < MC_1_19_2 StructureFeatureManager #else StructureManager #endif
|
public class WorldGenStructFeatManager extends #if MC_VER < MC_1_19_2 StructureFeatureManager #else StructureManager #endif
|
||||||
|
|||||||
+30
-11
@@ -27,15 +27,19 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGeneratio
|
|||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||||
|
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
import net.minecraft.server.level.WorldGenRegion;
|
||||||
#if MC_VER < MC_1_19_2
|
|
||||||
#endif
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#endif
|
||||||
|
|
||||||
public final class StepBiomes
|
public final class StepBiomes
|
||||||
{
|
{
|
||||||
public static final ChunkStatus STATUS = ChunkStatus.BIOMES;
|
public static final ChunkStatus STATUS = ChunkStatus.BIOMES;
|
||||||
@@ -52,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
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-5
@@ -27,11 +27,16 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
|||||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||||
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public final class StepFeatures
|
public final class StepFeatures
|
||||||
{
|
{
|
||||||
@@ -54,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -71,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));
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-11
@@ -28,17 +28,19 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParame
|
|||||||
|
|
||||||
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
import net.minecraft.server.level.WorldGenRegion;
|
||||||
#if MC_VER >= MC_1_17_1
|
|
||||||
#endif
|
|
||||||
#if MC_VER < MC_1_19_2
|
|
||||||
#endif
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#endif
|
||||||
|
|
||||||
public final class StepNoise
|
public final class StepNoise
|
||||||
{
|
{
|
||||||
private static final ChunkStatus STATUS = ChunkStatus.NOISE;
|
private static final ChunkStatus STATUS = ChunkStatus.NOISE;
|
||||||
@@ -56,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,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();
|
||||||
|
|||||||
+21
-6
@@ -27,12 +27,16 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGeneratio
|
|||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||||
|
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
import net.minecraft.server.level.WorldGenRegion;
|
||||||
#if MC_VER < MC_1_19_2
|
|
||||||
#endif
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public final class StepStructureReference
|
public final class StepStructureReference
|
||||||
{
|
{
|
||||||
private static final ChunkStatus STATUS = ChunkStatus.STRUCTURE_REFERENCES;
|
private static final ChunkStatus STATUS = ChunkStatus.STRUCTURE_REFERENCES;
|
||||||
@@ -55,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)
|
||||||
|
|||||||
+20
-5
@@ -30,10 +30,16 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParame
|
|||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
import net.minecraft.server.level.WorldGenRegion;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public final class StepStructureStart
|
public final class StepStructureStart
|
||||||
{
|
{
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||||
@@ -70,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)
|
||||||
|
|||||||
+22
-5
@@ -28,9 +28,14 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParame
|
|||||||
|
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
import net.minecraft.server.level.WorldGenRegion;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public final class StepSurface
|
public final class StepSurface
|
||||||
{
|
{
|
||||||
@@ -53,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
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
accessWidener v1 named
|
||||||
|
|
||||||
|
# used when determining where to save files to
|
||||||
|
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
|
||||||
|
|
||||||
|
# used when rendering
|
||||||
|
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
|
||||||
|
|
||||||
|
# used for grabbing vanilla rendered chunks
|
||||||
|
accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
|
||||||
|
|
||||||
|
#accessible method net/minecraft/client/renderer/LevelRenderer renderSectionLayer (Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V
|
||||||
|
|
||||||
|
# world generation
|
||||||
|
# accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
|
||||||
|
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
|
||||||
|
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
|
||||||
|
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
|
||||||
|
|
||||||
|
# lod generation from save file
|
||||||
|
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
|
||||||
|
accessible field net/minecraft/world/level/chunk/storage/IOWorker storage Lnet/minecraft/world/level/chunk/storage/RegionFileStorage;
|
||||||
|
accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage regionCache Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
|
||||||
|
accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage folder Ljava/nio/file/Path;
|
||||||
|
|
||||||
|
# grabbing textures
|
||||||
|
accessible class net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture
|
||||||
|
accessible method net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture getFrameX (I)I
|
||||||
|
accessible method net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture getFrameY (I)I
|
||||||
|
accessible field net/minecraft/client/renderer/texture/SpriteContents animatedTexture Lnet/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture;
|
||||||
|
accessible field net/minecraft/client/renderer/texture/SpriteContents originalImage Lcom/mojang/blaze3d/platform/NativeImage;
|
||||||
|
|
||||||
|
# UI stuff
|
||||||
|
accessible field net/minecraft/client/gui/components/AbstractButton SPRITES Lnet/minecraft/client/gui/components/WidgetSprites;
|
||||||
|
# Handles inserting the config button
|
||||||
|
accessible field net/minecraft/client/gui/layouts/HeaderAndFooterLayout headerFrame Lnet/minecraft/client/gui/layouts/FrameLayout;
|
||||||
|
accessible field net/minecraft/client/gui/layouts/FrameLayout children Ljava/util/List;
|
||||||
|
accessible class net/minecraft/client/gui/layouts/FrameLayout$ChildContainer
|
||||||
|
accessible field net/minecraft/client/gui/layouts/LinearLayout wrapped Lnet/minecraft/client/gui/layouts/GridLayout;
|
||||||
|
|
||||||
|
# hacky stuff
|
||||||
|
accessible field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
|
||||||
|
mutable field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
|
||||||
|
accessible field net/minecraft/client/gui/components/AbstractSelectionList scrollAmount D # Hack to bypass vanilla's setScrollAmount's clamp
|
||||||
|
|
||||||
|
|
||||||
+1
-1
Submodule coreSubProjects updated: 87e5647379...7cd1a37914
+80
-61
@@ -1,55 +1,94 @@
|
|||||||
unimined.minecraft {
|
plugins {
|
||||||
fabric {
|
id "fabric-loom" version "1.6-SNAPSHOT"
|
||||||
loader rootProject.fabric_loader_version
|
}
|
||||||
accessWidener(project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener"))
|
|
||||||
|
|
||||||
skipInsertAw = true
|
loom {
|
||||||
|
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 {
|
||||||
|
client {
|
||||||
|
client()
|
||||||
|
setConfigName("Fabric Client")
|
||||||
|
ideConfigGenerated(true)
|
||||||
|
runDir("../run/client")
|
||||||
|
vmArgs("-Dio.netty.leakDetection.level=advanced")
|
||||||
|
programArgs("--username", "Dev")
|
||||||
|
}
|
||||||
|
server {
|
||||||
|
server()
|
||||||
|
setConfigName("Fabric Server")
|
||||||
|
ideConfigGenerated(true)
|
||||||
|
runDir("../run/server")
|
||||||
|
vmArgs("-Dio.netty.leakDetection.level=advanced")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remapJar {
|
||||||
|
inputFile = shadowJar.archiveFile
|
||||||
|
dependsOn shadowJar
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
// The addModJar basically embeds the mod to the built jar
|
// The addModJar basically embeds the mod to the built jar
|
||||||
addModJar
|
addModJar
|
||||||
include.extendsFrom addModJar
|
include.extendsFrom addModJar
|
||||||
modImplementation.extendsFrom addModJar
|
modImplementation.extendsFrom addModJar
|
||||||
dummy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def addMod(path, enabled) {
|
def addMod(path, enabled) {
|
||||||
if (enabled == "2")
|
if (enabled == "2")
|
||||||
dependencies { modImplementation(path) }
|
dependencies { modImplementation(path) }
|
||||||
else if (enabled == "1")
|
else if (enabled == "1")
|
||||||
dependencies { compileOnly(path) }
|
dependencies { modCompileOnly(path) }
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: There currently seems to be a bug which causes the regular addModJar to not work, swap back to the regular addModJar when fixed
|
|
||||||
def addModJar_(path) {
|
|
||||||
dependencies {
|
|
||||||
modImplementation(path)
|
|
||||||
include(path)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
annotationProcessor "javax.annotation:javax.annotation-api:1.3.2"
|
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||||
implementation("javax.annotation:javax.annotation-api:1.3.2")
|
mappings loom.layered() {
|
||||||
runtimeOnly "javax.annotation:javax.annotation-api:1.3.2"
|
// Mojmap mappings
|
||||||
compileOnly "javax.annotation:javax.annotation-api:1.3.2"
|
officialMojangMappings()
|
||||||
modImplementation "javax.annotation:javax.annotation-api:1.3.2"
|
// Parchment mappings (it adds parameter mappings & javadoc)
|
||||||
|
parchment("org.parchmentmc.data:parchment-${rootProject.parchment_version}@zip")
|
||||||
|
}
|
||||||
|
// Fabric loader
|
||||||
|
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||||
|
|
||||||
|
|
||||||
|
// annotationProcessor "javax.annotation:javax.annotation-api:1.3.2"
|
||||||
|
// implementation("javax.annotation:javax.annotation-api:1.3.2")
|
||||||
|
// runtimeOnly "javax.annotation:javax.annotation-api:1.3.2"
|
||||||
|
// compileOnly "javax.annotation:javax.annotation-api:1.3.2"
|
||||||
|
// modImplementation "javax.annotation:javax.annotation-api:1.3.2"
|
||||||
|
|
||||||
// Fabric API
|
// Fabric API
|
||||||
addModJar_(fabricApi.fabricModule("fabric-api-base", rootProject.fabric_api_version))
|
addModJar(fabricApi.module("fabric-api-base", rootProject.fabric_api_version))
|
||||||
addModJar_(fabricApi.fabricModule("fabric-lifecycle-events-v1", rootProject.fabric_api_version))
|
addModJar(fabricApi.module("fabric-lifecycle-events-v1", rootProject.fabric_api_version))
|
||||||
addModJar_(fabricApi.fabricModule("fabric-resource-loader-v0", rootProject.fabric_api_version))
|
addModJar(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version))
|
||||||
addModJar_(fabricApi.fabricModule("fabric-events-interaction-v0", rootProject.fabric_api_version))
|
addModJar(fabricApi.module("fabric-events-interaction-v0", rootProject.fabric_api_version))
|
||||||
addModJar_(fabricApi.fabricModule("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.fabricModule("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+
|
||||||
|
addModJar(fabricApi.module("fabric-screen-api-v1", rootProject.fabric_api_version))
|
||||||
|
addModJar(fabricApi.module("fabric-key-binding-api-v1", rootProject.fabric_api_version))
|
||||||
|
|
||||||
|
|
||||||
// Mod Menu
|
// Mod Menu
|
||||||
modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}")
|
modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Starlight
|
// Starlight
|
||||||
addMod("curse.maven:starlight-521783:${rootProject.starlight_version_fabric}", rootProject.enable_starlight)
|
addMod("curse.maven:starlight-521783:${rootProject.starlight_version_fabric}", rootProject.enable_starlight)
|
||||||
|
|
||||||
@@ -63,22 +102,23 @@ dependencies {
|
|||||||
modImplementation(fabricApi.module("fabric-rendering-data-attachment-v1", rootProject.fabric_api_version))
|
modImplementation(fabricApi.module("fabric-rendering-data-attachment-v1", rootProject.fabric_api_version))
|
||||||
modImplementation(fabricApi.module("fabric-rendering-fluids-v1", rootProject.fabric_api_version))
|
modImplementation(fabricApi.module("fabric-rendering-fluids-v1", rootProject.fabric_api_version))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lithium
|
// Lithium
|
||||||
addMod("maven.modrinth:lithium:${rootProject.lithium_version}", rootProject.enable_lithium)
|
addMod("maven.modrinth:lithium:${rootProject.lithium_version}", rootProject.enable_lithium)
|
||||||
|
|
||||||
// Iris
|
// Iris
|
||||||
addMod("maven.modrinth:iris:${rootProject.iris_version}", rootProject.enable_iris)
|
addMod("maven.modrinth:iris:${rootProject.iris_version}", rootProject.enable_iris)
|
||||||
|
|
||||||
// BCLib
|
// BCLib
|
||||||
addMod("com.github.quiqueck:BCLib:${rootProject.bclib_version}", rootProject.enable_bclib)
|
addMod("com.github.quiqueck:BCLib:${rootProject.bclib_version}", rootProject.enable_bclib)
|
||||||
|
|
||||||
// Canvas
|
// Canvas
|
||||||
addMod("io.vram:canvas-fabric-${project.canvas_version}", rootProject.enable_canvas)
|
addMod("io.vram:canvas-fabric-${project.canvas_version}", rootProject.enable_canvas)
|
||||||
|
|
||||||
// Immersive Portals
|
// Immersive Portals
|
||||||
if (rootProject.enable_immersive_portals == "1")
|
if (rootProject.enable_immersive_portals == "1") {
|
||||||
modCompileOnly ("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${project.immersive_portals_version}")
|
modCompileOnly("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${project.immersive_portals_version}")
|
||||||
|
}
|
||||||
else if (rootProject.enable_immersive_portals == "2") {
|
else if (rootProject.enable_immersive_portals == "2") {
|
||||||
modImplementation ("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${project.immersive_portals_version}") {
|
modImplementation ("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${project.immersive_portals_version}") {
|
||||||
exclude(group: "net.fabricmc.fabric-api")
|
exclude(group: "net.fabricmc.fabric-api")
|
||||||
@@ -98,12 +138,6 @@ dependencies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remapJar {
|
|
||||||
inputFile = shadowJar.archiveFile
|
|
||||||
dependsOn shadowJar
|
|
||||||
// classifier null
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
task deleteResources(type: Delete) {
|
task deleteResources(type: Delete) {
|
||||||
delete file("build/resources/main")
|
delete file("build/resources/main")
|
||||||
@@ -114,31 +148,16 @@ processResources {
|
|||||||
dependsOn(copyCommonLoaderResources)
|
dependsOn(copyCommonLoaderResources)
|
||||||
}
|
}
|
||||||
|
|
||||||
afterEvaluate {
|
runClient {
|
||||||
runClient {
|
dependsOn(copyCoreResources)
|
||||||
dependsOn(copyCoreResources)
|
dependsOn(copyCommonLoaderResources)
|
||||||
dependsOn(copyCommonLoaderResources)
|
|
||||||
// jvmArgs([ "-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg ])
|
// jvmArgs([ "-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg ])
|
||||||
finalizedBy(deleteResources)
|
finalizedBy(deleteResources)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//jar {
|
|
||||||
// classifier "dev"
|
|
||||||
//}
|
|
||||||
|
|
||||||
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) }
|
||||||
|
}
|
||||||
// def fabricLikeSources = project(":fabricLike").sourcesJar
|
|
||||||
// dependsOn fabricLikeSources
|
|
||||||
// from fabricLikeSources.archiveFile.map { zipTree(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
//components.java {
|
|
||||||
// withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
|
|
||||||
// skip()
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
@@ -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>
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
package com.seibel.distanthorizons.fabric;
|
package com.seibel.distanthorizons.fabric;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
||||||
import com.seibel.distanthorizons.common.rendering.SeamlessOverdraw;
|
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;
|
||||||
@@ -28,31 +28,38 @@ 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.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;
|
||||||
@@ -87,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");
|
||||||
@@ -115,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
|
||||||
@@ -127,18 +139,27 @@ 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(() ->
|
||||||
|
{
|
||||||
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
|
ChunkAccess chunk = level.getChunk(blockPos);
|
||||||
SharedApi.INSTANCE.chunkBlockChangedEvent(
|
if (chunk != null)
|
||||||
new ChunkWrapper(chunk, level, wrappedLevel),
|
{
|
||||||
wrappedLevel
|
//LOGGER.trace("attack block at blockPos: " + blockPos);
|
||||||
);
|
|
||||||
}
|
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
|
||||||
|
SharedApi.INSTANCE.chunkBlockChangedEvent(
|
||||||
|
new ChunkWrapper(chunk, level, wrappedLevel),
|
||||||
|
wrappedLevel
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,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(() ->
|
||||||
|
{
|
||||||
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
|
ChunkAccess chunk = level.getChunk(hitResult.getBlockPos());
|
||||||
SharedApi.INSTANCE.chunkBlockChangedEvent(
|
if (chunk != null)
|
||||||
new ChunkWrapper(chunk, level, wrappedLevel),
|
{
|
||||||
wrappedLevel
|
//LOGGER.trace("use block at blockPos: " + hitResult.getBlockPos());
|
||||||
);
|
|
||||||
|
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
|
||||||
|
SharedApi.INSTANCE.chunkBlockChangedEvent(
|
||||||
|
new ChunkWrapper(chunk, level, wrappedLevel),
|
||||||
|
wrappedLevel
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,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 //
|
||||||
@@ -193,27 +216,26 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
|
|
||||||
WorldRenderEvents.AFTER_SETUP.register((renderContext) ->
|
WorldRenderEvents.AFTER_SETUP.register((renderContext) ->
|
||||||
{
|
{
|
||||||
|
Mat4f projectionMatrix = McObjectConverter.Convert(renderContext.projectionMatrix());
|
||||||
|
|
||||||
|
Mat4f modelViewMatrix;
|
||||||
|
#if MC_VER < MC_1_20_6
|
||||||
|
modelViewMatrix = McObjectConverter.Convert(renderContext.matrixStack().last().pose());
|
||||||
|
#else
|
||||||
|
modelViewMatrix = McObjectConverter.Convert(renderContext.positionMatrix());
|
||||||
|
#endif
|
||||||
|
|
||||||
this.clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()),
|
this.clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()),
|
||||||
McObjectConverter.Convert(renderContext.matrixStack().last().pose()),
|
modelViewMatrix,
|
||||||
McObjectConverter.Convert(renderContext.projectionMatrix()),
|
projectionMatrix,
|
||||||
renderContext.tickDelta());
|
#if MC_VER < MC_1_21_1
|
||||||
|
renderContext.tickDelta()
|
||||||
|
#else
|
||||||
// experimental proof-of-concept option
|
renderContext.tickCounter().getGameTimeDeltaTicks()
|
||||||
if (Config.Client.Advanced.Graphics.AdvancedGraphics.seamlessOverdraw.get())
|
#endif
|
||||||
{
|
);
|
||||||
float[] matrixFloatArray = SeamlessOverdraw.overwriteMinecraftNearFarClipPlanes(renderContext.projectionMatrix(), renderContext.tickDelta());
|
|
||||||
|
|
||||||
#if MC_VER == MC_1_16_5
|
|
||||||
SeamlessOverdraw.applyLegacyProjectionMatrix(matrixFloatArray);
|
|
||||||
#elif MC_VER < MC_1_19_4
|
|
||||||
renderContext.projectionMatrix().load(FloatBuffer.wrap(matrixFloatArray));
|
|
||||||
#else
|
|
||||||
renderContext.projectionMatrix().set(matrixFloatArray);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Debug keyboard event
|
// Debug keyboard event
|
||||||
// FIXME: Use better hooks so it doesn't trigger key press events in text boxes
|
// FIXME: Use better hooks so it doesn't trigger key press events in text boxes
|
||||||
ClientTickEvents.END_CLIENT_TICK.register(client ->
|
ClientTickEvents.END_CLIENT_TICK.register(client ->
|
||||||
@@ -230,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()
|
||||||
@@ -269,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,9 @@ 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.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.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.*;
|
||||||
@@ -37,8 +39,16 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
|||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
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.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,12 +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();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@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(); }
|
||||||
@@ -72,10 +92,13 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
|
|||||||
// If sodium is installed Indium is also necessary in order to use the Fabric rendering API
|
// If sodium is installed Indium is also necessary in order to use the Fabric rendering API
|
||||||
if (!modChecker.isModLoaded("indium"))
|
if (!modChecker.isModLoaded("indium"))
|
||||||
{
|
{
|
||||||
// People don't read the crash logs!!!
|
String indiumMissingMessage = ModInfo.READABLE_NAME + " needs Indium to work with Sodium.\nPlease download Indium from https://modrinth.com/mod/indium";
|
||||||
// So, just put a notification, so they hopefully realise what's the problem (and dont just open issues)
|
LOGGER.fatal(indiumMissingMessage);
|
||||||
System.setProperty("java.awt.headless", "false"); // Required to make it work
|
|
||||||
JOptionPane.showMessageDialog(null, ModInfo.READABLE_NAME + " now relies on Indium to work with Sodium.\nPlease download Indium from https://modrinth.com/mod/indium", ModInfo.READABLE_NAME, JOptionPane.INFORMATION_MESSAGE);
|
if (!GraphicsEnvironment.isHeadless())
|
||||||
|
{
|
||||||
|
JOptionPane.showMessageDialog(null, indiumMissingMessage, ModInfo.READABLE_NAME, JOptionPane.INFORMATION_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
String errorMessage = "loading Distant Horizons. Distant Horizons requires Indium in order to run with Sodium.";
|
String errorMessage = "loading Distant Horizons. Distant Horizons requires Indium in order to run with Sodium.";
|
||||||
@@ -94,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()); }
|
||||||
@@ -112,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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+1
-1
@@ -65,4 +65,4 @@ public class MixinClientLevel
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
+2
-13
@@ -7,6 +7,7 @@ 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.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;
|
||||||
@@ -20,17 +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;
|
|
||||||
|
|
||||||
@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) { ClientApi.INSTANCE.clientLevelUnloadEvent(ClientLevelWrapper.getWrapper(this.level)); }
|
|
||||||
@Inject(method = "handleRespawn", at = @At("RETURN"))
|
|
||||||
void onHandleRespawnEnd(CallbackInfo ci) { ClientApi.INSTANCE.clientLevelLoadEvent(ClientLevelWrapper.getWrapper(this.level)); }
|
|
||||||
|
|
||||||
#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
|
||||||
@@ -38,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,4 +44,4 @@ public class MixinClientPacketListener
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
-69
@@ -1,69 +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.fabric.mixins.client;
|
|
||||||
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.NativeImage;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
|
||||||
import com.seibel.distanthorizons.common.util.ILightTextureMarker;
|
|
||||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(DynamicTexture.class)
|
|
||||||
public class MixinDynamicTexture implements ILightTextureMarker
|
|
||||||
{
|
|
||||||
/** Used to prevent accidentally using other dynamic textures as a lightmap */
|
|
||||||
@Unique
|
|
||||||
private boolean isLightTexture = false;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private NativeImage pixels;
|
|
||||||
|
|
||||||
@Inject(method = "upload()V", at = @At("HEAD"))
|
|
||||||
public void updateLightTexture(CallbackInfo ci)
|
|
||||||
{
|
|
||||||
// since the light map is always updated on the client render thread we should be able to access the client level at the same time
|
|
||||||
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
|
||||||
if (!this.isLightTexture
|
|
||||||
|| mc == null
|
|
||||||
|| mc.getWrappedClientLevel() == null
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//ApiShared.LOGGER.info("Lightmap update");
|
|
||||||
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
|
|
||||||
MinecraftRenderWrapper.INSTANCE.updateLightmap(this.pixels, clientLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void markLightTexture() { this.isLightTexture = true; }
|
|
||||||
|
|
||||||
}
|
|
||||||
+27
-13
@@ -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;
|
||||||
@@ -84,33 +79,49 @@ public class MixinLevelRenderer
|
|||||||
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
|
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
|
||||||
cancellable = true)
|
cancellable = true)
|
||||||
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
|
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
|
||||||
#else
|
#elif MC_VER < MC_1_20_6
|
||||||
@Inject(at = @At("HEAD"),
|
@Inject(at = @At("HEAD"),
|
||||||
method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
|
method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
|
||||||
cancellable = true)
|
cancellable = true)
|
||||||
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double camX, double camY, double camZ, Matrix4f projectionMatrix, CallbackInfo callback)
|
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double camX, double camY, double camZ, Matrix4f projectionMatrix, CallbackInfo callback)
|
||||||
|
#else
|
||||||
|
@Inject(at = @At("HEAD"),
|
||||||
|
method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;DDDLorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V",
|
||||||
|
cancellable = true)
|
||||||
|
private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f projectionMatrix, Matrix4f frustumMatrix, CallbackInfo callback)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#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();
|
||||||
|
|
||||||
Mat4f mcModelViewMatrix = McObjectConverter.Convert(matrixStackIn.last().pose());
|
Mat4f mcModelViewMatrix = McObjectConverter.Convert(matrixStackIn.last().pose());
|
||||||
|
|
||||||
#else
|
#elif MC_VER <= MC_1_20_4
|
||||||
// get the matrices directly from MC
|
// get the matrices directly from MC
|
||||||
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
|
||||||
|
// MC combined the model view and projection matricies
|
||||||
|
Mat4f mcModelViewMatrix = McObjectConverter.Convert(projectionMatrix);
|
||||||
|
Mat4f mcProjectionMatrix = new Mat4f();
|
||||||
|
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
|
||||||
@@ -126,9 +137,12 @@ public class MixinLevelRenderer
|
|||||||
#elif MC_VER < MC_1_20_1
|
#elif MC_VER < MC_1_20_1
|
||||||
@Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runUpdates(IZZ)I"), method = "renderLevel")
|
@Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runUpdates(IZZ)I"), method = "renderLevel")
|
||||||
public void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
|
public void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
|
||||||
|
#elif MC_VER < MC_1_20_6
|
||||||
|
@Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I"), method = "renderLevel")
|
||||||
|
private void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
|
||||||
#else
|
#else
|
||||||
@Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I"), method = "renderLevel")
|
@Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I"), method = "renderLevel")
|
||||||
private void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
|
private void callAfterRunUpdates(CallbackInfo ci)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
ChunkWrapper.syncedUpdateClientLightStatus();
|
ChunkWrapper.syncedUpdateClientLightStatus();
|
||||||
|
|||||||
+19
-7
@@ -20,9 +20,14 @@
|
|||||||
package com.seibel.distanthorizons.fabric.mixins.client;
|
package com.seibel.distanthorizons.fabric.mixins.client;
|
||||||
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.util.ILightTextureMarker;
|
import com.mojang.blaze3d.platform.NativeImage;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
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.Shadow;
|
||||||
@@ -35,13 +40,20 @@ public class MixinLightTexture
|
|||||||
{
|
{
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
private DynamicTexture lightTexture;
|
private NativeImage lightPixels;
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
public void markLightTexture(CallbackInfo ci)
|
@Inject(method = "updateLightTexture(F)V", at = @At("RETURN"))
|
||||||
|
public void updateLightTexture(float partialTicks, CallbackInfo ci)
|
||||||
{
|
{
|
||||||
//
|
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
((ILightTextureMarker) this.lightTexture).markLightTexture();
|
if (mc == null || mc.getWrappedClientLevel() == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
|
||||||
|
MinecraftRenderWrapper.INSTANCE.updateLightmap(this.lightPixels, clientLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+63
-12
@@ -1,17 +1,23 @@
|
|||||||
package com.seibel.distanthorizons.fabric.mixins.client;
|
package com.seibel.distanthorizons.fabric.mixins.client;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.config.EUpdateBranch;
|
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 net.minecraft.client.Minecraft;
|
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.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.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;
|
||||||
@@ -23,8 +29,23 @@ 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/>
|
||||||
|
* will always show the auto updater if set to true.
|
||||||
|
*/
|
||||||
|
@Unique
|
||||||
|
private static final boolean DEBUG_ALWAYS_SHOW_UPDATER = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_20_2
|
#if MC_VER < MC_1_20_2
|
||||||
#if MC_VER == MC_1_20_1
|
#if MC_VER == MC_1_20_1
|
||||||
@Redirect(
|
@Redirect(
|
||||||
@@ -41,17 +62,17 @@ public class MixinMinecraft
|
|||||||
public void onOpenScreen(Minecraft instance, Screen guiScreen)
|
public void onOpenScreen(Minecraft instance, Screen guiScreen)
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
if (!Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get()) // Don't do anything if the user doesn't want it
|
if (!Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() && !DEBUG_ALWAYS_SHOW_UPDATER) // Don't do anything if the user doesn't want it
|
||||||
{
|
{
|
||||||
instance.setScreen(guiScreen); // Sets the screen back to the vanilla screen as if nothing ever happened
|
instance.setScreen(guiScreen); // Sets the screen back to the vanilla screen as if nothing ever happened
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SelfUpdater.onStart())
|
if (SelfUpdater.onStart() || DEBUG_ALWAYS_SHOW_UPDATER)
|
||||||
{
|
{
|
||||||
instance.setScreen(new UpdateModScreen(
|
instance.setScreen(new UpdateModScreen(
|
||||||
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() == EUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()): GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
|
(Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()): GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -69,15 +90,31 @@ public class MixinMinecraft
|
|||||||
private void buildInitialScreens(Runnable runnable)
|
private void buildInitialScreens(Runnable runnable)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() // Don't do anything if the user doesn't want it
|
DEBUG_ALWAYS_SHOW_UPDATER ||
|
||||||
&& SelfUpdater.onStart()
|
(
|
||||||
)
|
// Don't do anything if the user doesn't want it
|
||||||
|
Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get()
|
||||||
|
&& 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() == EUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()) : GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
|
versionId
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -86,7 +123,21 @@ 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(); }
|
||||||
|
|
||||||
}
|
}
|
||||||
+103
-28
@@ -23,7 +23,6 @@ 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
|
||||||
@@ -31,51 +30,127 @@ import net.minecraft.network.chat.TranslatableComponent;
|
|||||||
#endif
|
#endif
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
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.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_20_6
|
||||||
|
import net.minecraft.client.gui.layouts.LinearLayout;
|
||||||
|
import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
#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
|
||||||
*
|
*
|
||||||
* @author coolGi
|
* @author coolGi
|
||||||
* @version 12-02-2021
|
* @version 2024-5-20
|
||||||
*/
|
*/
|
||||||
@Mixin(OptionsScreen.class)
|
@Mixin(OptionsScreen.class)
|
||||||
public class MixinOptionsScreen extends Screen
|
public class MixinOptionsScreen extends Screen
|
||||||
{
|
{
|
||||||
// Get the texture for the button
|
/** Texture used for the config opening button */
|
||||||
private static final ResourceLocation ICON_TEXTURE = new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
|
@Unique
|
||||||
protected MixinOptionsScreen(Component title)
|
private static final ResourceLocation ICON_TEXTURE =
|
||||||
{
|
#if MC_VER < MC_1_21_1
|
||||||
super(title);
|
new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
|
||||||
}
|
#else
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
|
||||||
|
#endif
|
||||||
|
|
||||||
@Inject(at = @At("HEAD"), method = "init")
|
|
||||||
|
@Unique
|
||||||
|
private TexturedButtonWidget optionsButton = null;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_20_6
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
protected HeaderAndFooterLayout layout;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// constructors //
|
||||||
|
//==============//
|
||||||
|
|
||||||
|
protected MixinOptionsScreen(Component title) { super(title); }
|
||||||
|
|
||||||
|
@Inject(at = @At("RETURN"), method = "init")
|
||||||
private void lodconfig$init(CallbackInfo ci)
|
private void lodconfig$init(CallbackInfo ci)
|
||||||
{
|
{
|
||||||
if (Config.Client.optionsButton.get())
|
if (Config.Client.optionsButton.get())
|
||||||
this. #if MC_VER < MC_1_17_1 addButton #else addRenderableWidget #endif
|
{
|
||||||
(new TexturedButtonWidget(
|
#if MC_VER < MC_1_17_1
|
||||||
// Where the button is on the screen
|
this.addButton(this.getOptionsButton());
|
||||||
this.width / 2 - 180, this.height / 6 - 12,
|
#elif MC_VER < MC_1_20_6
|
||||||
// Width and height of the button
|
this.addRenderableWidget(this.getOptionsButton());
|
||||||
20, 20,
|
#else
|
||||||
// Offset
|
|
||||||
0, 0,
|
// add the button so it's rendered
|
||||||
// Some textuary stuff
|
this.addRenderableWidget(this.getOptionsButton());
|
||||||
20, ICON_TEXTURE, 20, 40,
|
|
||||||
// Create the button and tell it where to go
|
// add the button to the correct location in the UI
|
||||||
// For now it goes to the client option by default
|
// TODO is there a better way to do this instead of using access transformers to inject into the exact UI elements?
|
||||||
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(GetConfigScreen.getScreen(this)),
|
LinearLayout layout = (LinearLayout) this.layout.headerFrame.children.get(0).child;
|
||||||
// Add a title to the utton
|
|
||||||
#if MC_VER < MC_1_19_2
|
// determine how wide the other option buttons are so we can put our botton to the left of them all
|
||||||
new TranslatableComponent(ModInfo.ID + ".title")));
|
AtomicInteger width = new AtomicInteger(0);
|
||||||
#else
|
layout.visitChildren(x -> { width.addAndGet(x.getWidth()); });
|
||||||
Component.translatable(ModInfo.ID + ".title")));
|
width.addAndGet(-10); // padding between the DH button and the FOV slider
|
||||||
#endif
|
|
||||||
|
layout.wrapped.addChild(this.getOptionsButton(), 1, 2, (settings) -> { settings.paddingLeft(width.get() * -1); });
|
||||||
|
layout.arrangeElements();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper methods //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
public TexturedButtonWidget getOptionsButton()
|
||||||
|
{
|
||||||
|
if (this.optionsButton == null)
|
||||||
|
{
|
||||||
|
this.optionsButton
|
||||||
|
= new TexturedButtonWidget(
|
||||||
|
// Where the button is on the screen
|
||||||
|
this.width / 2 - 180, this.height / 6 - 12,
|
||||||
|
// Width and height of the button
|
||||||
|
20, 20,
|
||||||
|
// texture UV Offset
|
||||||
|
0, 0,
|
||||||
|
// Some textuary stuff
|
||||||
|
20, ICON_TEXTURE, 20, 40,
|
||||||
|
// Create the button and tell it where to go
|
||||||
|
// For now it goes to the client option by default
|
||||||
|
(buttonWidget) -> Objects.requireNonNull(this.minecraft).setScreen(GetConfigScreen.getScreen(this)),
|
||||||
|
// Add a title to the button
|
||||||
|
#if MC_VER < MC_1_19_2
|
||||||
|
new TranslatableComponent(ModInfo.ID + ".title"));
|
||||||
|
#else
|
||||||
|
Component.translatable(ModInfo.ID + ".title"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.optionsButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
-60
@@ -1,60 +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.fabric.mixins.server.unsafe;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
|
|
||||||
//FIXME: Is this still needed?
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
|
|
||||||
import net.minecraft.util.ThreadingDetector;
|
|
||||||
import org.spongepowered.asm.mixin.Mutable;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.concurrent.Semaphore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Why does this exist? But okay! (Will be probably removed when the experimental generator is done)
|
|
||||||
* FIXME: Recheck this
|
|
||||||
*/
|
|
||||||
@Mixin(ThreadingDetector.class)
|
|
||||||
public class MixinThreadingDetector
|
|
||||||
{
|
|
||||||
@Mutable
|
|
||||||
@Shadow
|
|
||||||
private Semaphore lock;
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void setSemaphore(CallbackInfo ci)
|
|
||||||
{
|
|
||||||
this.lock = new Semaphore(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
|
|
||||||
@Mixin(ServerLevel.class)
|
|
||||||
public class MixinThreadingDetector { } //FIXME: Is there some way to make this file just not be added?
|
|
||||||
#endif
|
|
||||||
+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 */ }
|
||||||
|
|
||||||
|
}
|
||||||
+4
-3
@@ -1,11 +1,11 @@
|
|||||||
package com.seibel.distanthorizons.fabric.wrappers.modAccessor;
|
package com.seibel.distanthorizons.fabric.wrappers.modAccessor;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IBCLibAccessor;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IBCLibAccessor;
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 || MC_VER == MC_1_20_4 // These versions either don't have BCLib, or the implementation is different
|
#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
|
||||||
#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) // 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
|
||||||
|
|||||||
+4
@@ -22,7 +22,11 @@ package com.seibel.distanthorizons.fabric.wrappers.modAccessor;
|
|||||||
#if MC_VER >= MC_1_19_4
|
#if MC_VER >= MC_1_19_4
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
import net.coderbot.iris.Iris;
|
import net.coderbot.iris.Iris;
|
||||||
|
#else
|
||||||
|
import net.irisshaders.iris.Iris;
|
||||||
|
#endif
|
||||||
import net.irisshaders.iris.api.v0.IrisApi;
|
import net.irisshaders.iris.api.v0.IrisApi;
|
||||||
|
|
||||||
public class IrisAccessor implements IIrisAccessor
|
public class IrisAccessor implements IIrisAccessor
|
||||||
|
|||||||
+90
-95
@@ -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;
|
||||||
@@ -40,103 +38,100 @@ import net.minecraft.world.entity.Entity;
|
|||||||
import net.minecraft.world.entity.EntityType;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
"minVersion": "0.8",
|
"minVersion": "0.8",
|
||||||
"package": "com.seibel.distanthorizons.fabric.mixins",
|
"package": "com.seibel.distanthorizons.fabric.mixins",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"server.unsafe.MixinThreadingDetector",
|
|
||||||
"server.MixinChunkGenerator",
|
"server.MixinChunkGenerator",
|
||||||
"server.MixinChunkMap",
|
"server.MixinChunkMap",
|
||||||
"server.MixinUtilBackgroundThread"
|
"server.MixinUtilBackgroundThread",
|
||||||
|
"server.MixinServerPlayer"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinClientLevel",
|
"client.MixinClientLevel",
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
"client.MixinFogRenderer",
|
"client.MixinFogRenderer",
|
||||||
"client.MixinGameRenderer",
|
"client.MixinGameRenderer",
|
||||||
"client.MixinLevelRenderer",
|
"client.MixinLevelRenderer",
|
||||||
"client.MixinDynamicTexture",
|
|
||||||
"client.MixinLightTexture",
|
"client.MixinLightTexture",
|
||||||
"client.MixinOptionsScreen",
|
"client.MixinOptionsScreen",
|
||||||
"client.MixinMinecraft",
|
"client.MixinMinecraft",
|
||||||
@@ -26,4 +25,4 @@
|
|||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
},
|
},
|
||||||
"plugin": "com.seibel.distanthorizons.fabric.mixins.FabricMixinPlugin"
|
"plugin": "com.seibel.distanthorizons.fabric.mixins.FabricMixinPlugin"
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,6 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"suggests": {
|
"suggests": {
|
||||||
"blendium": "*"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"breaks": $fabric_incompatibility_list,
|
"breaks": $fabric_incompatibility_list,
|
||||||
|
|||||||
+86
-87
@@ -1,44 +1,101 @@
|
|||||||
unimined.minecraft {
|
plugins {
|
||||||
minecraftForge {
|
// Note: This is only needed for multi-loader projects
|
||||||
loader forge_version
|
// The main architectury loom version is set at the start of the root build.gradle
|
||||||
mixinConfig("DistantHorizons.forge.mixins.json")
|
id "architectury-plugin" version "3.4-SNAPSHOT"
|
||||||
|
}
|
||||||
|
|
||||||
file("build/sourcesSets/main/META-INF/").mkdirs()
|
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_21
|
||||||
accessTransformer(aw2at(
|
|
||||||
project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener"),
|
architectury {
|
||||||
file("build/sourcesSets/main/META-INF/accesstransformer.cfg") // We'd wanna output the access transformer to somewhere where it'll only appear in the final jar
|
platformSetupLoomIde()
|
||||||
))
|
forge()
|
||||||
|
}
|
||||||
|
|
||||||
|
//loom {
|
||||||
|
// forge {
|
||||||
|
// convertAccessWideners.set(true)
|
||||||
|
// extraAccessWideners.add("lod.accesswidener")
|
||||||
|
// mixinConfigs("DistantHorizons.mixins.json")
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
loom {
|
||||||
|
silentMojangMappingsLicense() // Shut the licencing warning
|
||||||
|
accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
||||||
|
|
||||||
|
forge {
|
||||||
|
convertAccessWideners = true
|
||||||
|
extraAccessWideners.add loom.accessWidenerPath.get().asFile.name
|
||||||
|
|
||||||
|
mixinConfigs = [
|
||||||
|
"DistantHorizons.forge.mixins.json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// "runs" isn't required, but when we do need it then it can be useful
|
||||||
|
runs {
|
||||||
|
client {
|
||||||
|
client()
|
||||||
|
setConfigName("Forge Client")
|
||||||
|
ideConfigGenerated(false)
|
||||||
|
runDir("../run/client")
|
||||||
|
vmArgs("-Dio.netty.leakDetection.level=advanced")
|
||||||
|
programArgs("--username", "Dev")
|
||||||
|
}
|
||||||
|
server {
|
||||||
|
server()
|
||||||
|
setConfigName("Forge Server")
|
||||||
|
ideConfigGenerated(false)
|
||||||
|
runDir("../run/server")
|
||||||
|
vmArgs("-Dio.netty.leakDetection.level=advanced")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remapJar {
|
||||||
|
inputFile = shadowJar.archiveFile
|
||||||
|
dependsOn shadowJar
|
||||||
|
}
|
||||||
|
|
||||||
def addMod(path, enabled) {
|
def addMod(path, enabled) {
|
||||||
if (enabled == "2")
|
if (enabled == "2")
|
||||||
dependencies { modImplementation(path) }
|
dependencies { implementation(path) }
|
||||||
else if (enabled == "1")
|
else if (enabled == "1")
|
||||||
dependencies { compileOnly(path) }
|
dependencies { modCompileOnly(path) }
|
||||||
}
|
}
|
||||||
dependencies {
|
|
||||||
// Architectury API
|
|
||||||
// if (minecraft_version == "1.16.5") {
|
|
||||||
// implementation("me.shedaniel:architectury-forge:${rootProject.architectury_version}")
|
|
||||||
// } else {
|
|
||||||
// implementation("dev.architectury:architectury-forge:${rootProject.architectury_version}")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Starlight
|
dependencies {
|
||||||
addMod("curse.maven:starlight-forge-526854:${rootProject.starlight_version_forge}", rootProject.enable_starlight_forge)
|
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||||
// annotationProcessor "org.spongepowered:mixin:0.8.4:processor"
|
mappings loom.layered() {
|
||||||
|
// Mojmap mappings
|
||||||
|
officialMojangMappings()
|
||||||
|
// Parchment mappings (it adds parameter mappings & javadoc)
|
||||||
|
parchment("org.parchmentmc.data:parchment-${rootProject.parchment_version}@zip")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forge
|
||||||
|
forge "net.minecraftforge:forge:${rootProject.minecraft_version}-${rootProject.forge_version}"
|
||||||
|
|
||||||
addMod("curse.maven:TerraForged-363820:${rootProject.terraforged_version}", rootProject.enable_terraforged)
|
addMod("curse.maven:TerraForged-363820:${rootProject.terraforged_version}", rootProject.enable_terraforged)
|
||||||
|
|
||||||
addMod("curse.maven:TerraFirmaCraft-302973:4616004", rootProject.enable_terrafirmacraft)
|
addMod("curse.maven:TerraFirmaCraft-302973:4616004", rootProject.enable_terrafirmacraft)
|
||||||
|
|
||||||
// annotationProcessor "org.spongepowered:mixin:0.8.5:processor"
|
|
||||||
|
|
||||||
// if (System.getProperty("idea.sync.active") != "true") {
|
|
||||||
// annotationProcessor "org.spongepowered:mixin:0.8.4:processor"
|
if ( // Only run on MC 1.20.6 or later
|
||||||
// }
|
// FIXME: Add an environment variable for the Major, Minor, and Patch version number of Minecraft
|
||||||
|
minecraft_version.split("\\.")[1].toInteger() >= 20 &&
|
||||||
|
(
|
||||||
|
minecraft_version.split("\\.").length > 1 && // Incase there isn't a minor version
|
||||||
|
minecraft_version.split("\\.")[2].toInteger() >= 6
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// (potential) hack fix, force jopt-simple to be exactly 5.0.4 because Mojang ships that version, but some transitive dependencies request 6.0+
|
||||||
|
implementation('net.sf.jopt-simple:jopt-simple:5.0.4') //{ version { strictly '5.0.4' } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task deleteResources(type: Delete) {
|
||||||
|
delete file("build/resources/main")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('copyAllResources') {
|
tasks.register('copyAllResources') {
|
||||||
@@ -46,70 +103,12 @@ tasks.register('copyAllResources') {
|
|||||||
dependsOn(copyCommonLoaderResources)
|
dependsOn(copyCommonLoaderResources)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
dependsOn(tasks.named('copyAllResources'))
|
dependsOn(tasks.named('copyAllResources'))
|
||||||
}
|
}
|
||||||
|
|
||||||
afterEvaluate {
|
tasks.named('runClient') {
|
||||||
runClient {
|
dependsOn(tasks.named('copyAllResources'))
|
||||||
dependsOn(tasks.named('copyAllResources'))
|
finalizedBy(deleteResources)
|
||||||
}
|
|
||||||
|
|
||||||
// TODO this isn't a great place for these, but `tasks.build.doLast` doesn't always work and I'm not sure of a better place right now
|
|
||||||
tasks.runClient.doFirst {
|
|
||||||
// TODO can we just ignore these folders instead?
|
|
||||||
// deleting them may cause issues if the OS locks the files
|
|
||||||
// and it feels hacky
|
|
||||||
delete file("../common/build/libs")
|
|
||||||
delete file("../coreSubProjects/core/build/libs")
|
|
||||||
delete file("../coreSubProjects/api/build/libs")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remapJar {
|
|
||||||
inputFile = shadowJar.archiveFile
|
|
||||||
dependsOn shadowJar
|
|
||||||
// classifier null
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sourcesJar {
|
|
||||||
def commonSources = project(":common").sourcesJar
|
|
||||||
dependsOn commonSources
|
|
||||||
from commonSources.archiveFile.map { zipTree(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
//components.java {
|
|
||||||
// withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
|
|
||||||
// skip()
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO this was specifically added for MC 1.20.4 and should not be used on MC versions prior to it
|
|
||||||
// source: https://github.com/MinecraftForge/MinecraftForge/blob/5d0047753dfac0caaf5d97cc3f5c9a8b0990cb44/mdk/build.gradle#L209-L217
|
|
||||||
//
|
|
||||||
// Merge the resources and classes into the same directory.
|
|
||||||
// This is done because java expects modules to be in a single directory.
|
|
||||||
// And if we have it in multiple we have to do performance intensive hacks like having the UnionFileSystem
|
|
||||||
// This will eventually be migrated to ForgeGradle so modders don't need to manually do it. But that is later.
|
|
||||||
sourceSets.each {
|
|
||||||
if ( // Only run on MC 1.20.4 or later
|
|
||||||
// FIXME: Add an environment variable for the Major, Minor, and Patch version number of Minecraft
|
|
||||||
minecraft_version.split("\\.")[1].toInteger() >= 20 &&
|
|
||||||
(
|
|
||||||
minecraft_version.split("\\.").length > 1 && // Incase there isn't a minor version
|
|
||||||
minecraft_version.split("\\.")[2].toInteger() >= 4
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
// all of our code and resources should be in the sourceSets/main/ folder for Forge 1.20.4+
|
|
||||||
def dir = layout.buildDirectory.dir("sourcesSets/$it.name")
|
|
||||||
println "source name: [" + it.name + "]"// as of 2024-2-4 "it.name" only returned "main" and "test"
|
|
||||||
it.output.resourcesDir = dir
|
|
||||||
it.java.destinationDirectory = dir
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -76,8 +75,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
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -124,7 +121,7 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
LOGGER.info("level load");
|
LOGGER.info("level load");
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
LevelAccessor level = event.getWorld();
|
LevelAccessor level = event.getWorld();
|
||||||
#else
|
#else
|
||||||
@@ -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,11 +141,11 @@ 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");
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
LevelAccessor level = event.getWorld();
|
LevelAccessor level = event.getWorld();
|
||||||
#else
|
#else
|
||||||
@@ -173,61 +170,76 @@ 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)
|
||||||
{
|
{
|
||||||
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(level);
|
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(level);
|
||||||
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 //
|
||||||
//===========//
|
//===========//
|
||||||
@@ -328,9 +280,7 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
#elif MC_VER >= MC_1_18_2
|
#elif MC_VER >= MC_1_18_2
|
||||||
if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_SOLID_BLOCKS)
|
if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_SOLID_BLOCKS)
|
||||||
#else
|
#else
|
||||||
// FIXME: Is this the correct location for 1.16 & 1.17???
|
if (event.type.equals(TickEvent.RenderTickEvent.Type.RENDER))
|
||||||
// I couldnt find anything for rendering after the level, so is rendering after overlays ok?
|
|
||||||
if (event.type.equals(TickEvent.RenderTickEvent.Type.WORLD))
|
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -347,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
|
||||||
@@ -70,7 +75,7 @@ import java.util.function.Consumer;
|
|||||||
* If you are looking for the real start of the mod
|
* If you are looking for the real start of the mod
|
||||||
* check out the ClientProxy.
|
* check out the ClientProxy.
|
||||||
*/
|
*/
|
||||||
@Mod("distanthorizons") // TODO: Change it back to ModInfo.ID when forge works
|
@Mod(ModInfo.ID)
|
||||||
public class ForgeMain extends AbstractModInitializer
|
public class ForgeMain extends AbstractModInitializer
|
||||||
{
|
{
|
||||||
public ForgeMain()
|
public ForgeMain()
|
||||||
@@ -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());
|
||||||
});
|
});
|
||||||
@@ -130,4 +153,4 @@ public class ForgeMain extends AbstractModInitializer
|
|||||||
@Override
|
@Override
|
||||||
protected void runDelayedSetup() { SingletonInjector.INSTANCE.runDelayedSetup(); }
|
protected void runDelayedSetup() { SingletonInjector.INSTANCE.runDelayedSetup(); }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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
|
@SubscribeEvent
|
||||||
public void serverChunkSaveEvent(ChunkEvent.Unload event)
|
public void playerLoggedInEvent(PlayerEvent.PlayerLoggedInEvent event)
|
||||||
{
|
{
|
||||||
ILevelWrapper levelWrapper = ProxyUtil.getLevelWrapper(GetEventLevel(event));
|
this.serverApi.serverPlayerJoinEvent(getServerPlayerWrapper(event));
|
||||||
|
}
|
||||||
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
|
@SubscribeEvent
|
||||||
this.serverApi.serverChunkSaveEvent(chunk, levelWrapper);
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -26,4 +26,4 @@ public class MixinClientPacketListener
|
|||||||
ClientApi.INSTANCE.onClientOnlyDisconnected();
|
ClientApi.INSTANCE.onClientOnlyDisconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
-74
@@ -1,74 +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.forge.mixins.client;
|
|
||||||
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.NativeImage;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
|
||||||
import com.seibel.distanthorizons.common.util.ILightTextureMarker;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
@Mixin(DynamicTexture.class)
|
|
||||||
public abstract class MixinDynamicTexture implements ILightTextureMarker
|
|
||||||
{
|
|
||||||
/** Used to prevent accidentally using other dynamic textures as a lightmap */
|
|
||||||
@Unique
|
|
||||||
private boolean isLightTexture = false;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private NativeImage pixels;
|
|
||||||
|
|
||||||
@Inject(method = "upload()V", at = @At("HEAD"))
|
|
||||||
public void updateLightTexture(CallbackInfo ci)
|
|
||||||
{
|
|
||||||
// since the light map is always updated on the client render thread we should be able to access the client level at the same time
|
|
||||||
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
|
||||||
if (!this.isLightTexture
|
|
||||||
|| mc == null
|
|
||||||
|| mc.getWrappedClientLevel() == null
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//ApiShared.LOGGER.info("Lightmap update");
|
|
||||||
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
|
|
||||||
MinecraftRenderWrapper.INSTANCE.updateLightmap(this.pixels, clientLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void markLightTexture() { this.isLightTexture = true; }
|
|
||||||
|
|
||||||
}
|
|
||||||
+14
-23
@@ -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;
|
||||||
@@ -29,19 +33,14 @@ import net.minecraft.client.renderer.GameRenderer;
|
|||||||
import net.minecraft.client.renderer.LightTexture;
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
#endif
|
#endif
|
||||||
import com.seibel.distanthorizons.common.rendering.SeamlessOverdraw;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
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 +49,7 @@ 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;
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
#if MC_VER < MC_1_17_1
|
#if MC_VER < MC_1_17_1
|
||||||
import org.lwjgl.opengl.GL15;
|
import org.lwjgl.opengl.GL15;
|
||||||
@@ -69,7 +68,8 @@ import org.lwjgl.opengl.GL15;
|
|||||||
@Mixin(LevelRenderer.class)
|
@Mixin(LevelRenderer.class)
|
||||||
public class MixinLevelRenderer
|
public class MixinLevelRenderer
|
||||||
{
|
{
|
||||||
@Shadow
|
@Nullable
|
||||||
|
@Shadow //# if MC_VER >= MC_1_20_4 (remap = false) # endif
|
||||||
private ClientLevel level;
|
private ClientLevel level;
|
||||||
@Unique
|
@Unique
|
||||||
private static float previousPartialTicks = 0;
|
private static float previousPartialTicks = 0;
|
||||||
@@ -112,11 +112,16 @@ public class MixinLevelRenderer
|
|||||||
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
|
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
|
||||||
cancellable = true)
|
cancellable = true)
|
||||||
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
|
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
|
||||||
#else
|
#elif MC_VER < MC_1_20_4
|
||||||
@Inject(at = @At("HEAD"),
|
@Inject(at = @At("HEAD"),
|
||||||
method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
|
method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
|
||||||
cancellable = true)
|
cancellable = true)
|
||||||
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double camX, double camY, double camZ, Matrix4f projectionMatrix, CallbackInfo callback)
|
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double camX, double camY, double camZ, Matrix4f projectionMatrix, CallbackInfo callback)
|
||||||
|
#else
|
||||||
|
@Inject(at = @At("HEAD"),
|
||||||
|
method = "renderSectionLayer",
|
||||||
|
cancellable = true)
|
||||||
|
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double camX, double camY, double camZ, Matrix4f projectionMatrix, CallbackInfo callback)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
// get MC's model view and projection matrices
|
// get MC's model view and projection matrices
|
||||||
@@ -141,20 +146,6 @@ public class MixinLevelRenderer
|
|||||||
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, Minecraft.getInstance().getFrameTime());
|
||||||
|
|
||||||
// experimental proof-of-concept option
|
|
||||||
if (Config.Client.Advanced.Graphics.AdvancedGraphics.seamlessOverdraw.get())
|
|
||||||
{
|
|
||||||
float[] matrixFloatArray = SeamlessOverdraw.overwriteMinecraftNearFarClipPlanes(mcProjectionMatrix, previousPartialTicks);
|
|
||||||
|
|
||||||
#if MC_VER == MC_1_16_5
|
|
||||||
SeamlessOverdraw.applyLegacyProjectionMatrix(matrixFloatArray);
|
|
||||||
#elif MC_VER < MC_1_19_4
|
|
||||||
projectionMatrix.load(FloatBuffer.wrap(matrixFloatArray));
|
|
||||||
#else
|
|
||||||
projectionMatrix.set(matrixFloatArray);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (renderType.equals(RenderType.translucent()))
|
else if (renderType.equals(RenderType.translucent()))
|
||||||
{
|
{
|
||||||
|
|||||||
+21
-7
@@ -20,10 +20,13 @@
|
|||||||
package com.seibel.distanthorizons.forge.mixins.client;
|
package com.seibel.distanthorizons.forge.mixins.client;
|
||||||
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.util.ILightTextureMarker;
|
import com.mojang.blaze3d.platform.NativeImage;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@@ -35,11 +38,22 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
@Mixin(LightTexture.class)
|
@Mixin(LightTexture.class)
|
||||||
public class MixinLightTexture
|
public class MixinLightTexture
|
||||||
{
|
{
|
||||||
@Shadow
|
@Shadow //# if MC_VER >= MC_1_20_4 (remap = false) # endif
|
||||||
@Final
|
@Final
|
||||||
private DynamicTexture lightTexture;
|
private NativeImage lightPixels;
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
public void markLightTexture(CallbackInfo ci) { ((ILightTextureMarker) this.lightTexture).markLightTexture(); }
|
@Inject(method = "updateLightTexture(F)V", at = @At("RETURN"))
|
||||||
|
public void updateLightTexture(float partialTicks, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
if (mc == null || mc.getWrappedClientLevel() == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
|
||||||
|
MinecraftRenderWrapper.INSTANCE.updateLightmap(this.lightPixels, clientLevel);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-5
@@ -1,7 +1,9 @@
|
|||||||
package com.seibel.distanthorizons.forge.mixins.client;
|
package com.seibel.distanthorizons.forge.mixins.client;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.config.EUpdateBranch;
|
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;
|
||||||
@@ -51,7 +55,7 @@ public class MixinMinecraft
|
|||||||
{
|
{
|
||||||
instance.setScreen(new UpdateModScreen(
|
instance.setScreen(new UpdateModScreen(
|
||||||
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() == EUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()): GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
|
(Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()): GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -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() == EUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()) : GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
|
versionId
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -92,4 +108,4 @@ public class MixinMinecraft
|
|||||||
SelfUpdater.onClose();
|
SelfUpdater.onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
-156
@@ -1,156 +0,0 @@
|
|||||||
package com.seibel.distanthorizons.forge.mixins.client;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
|
|
||||||
import com.seibel.distanthorizons.api.interfaces.world.IDhApiDimensionTypeWrapper;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.DimensionTypeWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.file.structure.LocalSaveStructure;
|
|
||||||
import com.seibel.distanthorizons.core.level.DhServerLevel;
|
|
||||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
|
||||||
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 net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.util.worldupdate.WorldUpgrader;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
|
||||||
import net.minecraft.world.level.dimension.LevelStem;
|
|
||||||
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
|
||||||
import net.minecraft.world.level.storage.DimensionDataStorage;
|
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
#if FALSE
|
|
||||||
@Mixin(WorldUpgrader.class)
|
|
||||||
public class MixinWorldUpgrader {
|
|
||||||
static class FakeLevelWrapper implements IServerLevelWrapper {
|
|
||||||
private Path saveFolder;
|
|
||||||
private LevelStem stem;
|
|
||||||
private DimensionType dimension;
|
|
||||||
private DimensionTypeWrapper dimensionTypeWrapper;
|
|
||||||
|
|
||||||
public FakeLevelWrapper(LevelStorageSource.LevelStorageAccess storage, WorldGenSettings gen, ResourceKey<Level> dim) {
|
|
||||||
saveFolder = storage.getDimensionPath(dim);
|
|
||||||
stem = gen.dimensions().getOrThrow(WorldGenSettings.levelToLevelStem(dim));
|
|
||||||
dimension = stem.typeHolder().value();
|
|
||||||
dimensionTypeWrapper = DimensionTypeWrapper.getDimensionTypeWrapper(dimension);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EDhApiLevelType getLevelType() {
|
|
||||||
return EDhApiLevelType.SERVER_LEVEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IDhApiDimensionTypeWrapper getDimensionType() {
|
|
||||||
return dimensionTypeWrapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBlockLight(int x, int y, int z) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSkyLight(int x, int y, int z) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasCeiling() {
|
|
||||||
return dimension.hasCeiling();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasSkyLight() {
|
|
||||||
return dimension.hasSkyLight();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight() {
|
|
||||||
return dimension.height();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMinHeight() {
|
|
||||||
return dimension.minY();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasChunkLoaded(int chunkX, int chunkZ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBlockStateWrapper getBlockState(DhBlockPos pos) {
|
|
||||||
return BlockStateWrapper.AIR;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBiomeWrapper getBiome(DhBlockPos pos) {
|
|
||||||
throw new UnsupportedOperationException("Not implemented yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getWrappedMcObject() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public IClientLevelWrapper tryGetClientLevelWrapper() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getSaveFolder() {
|
|
||||||
return saveFolder.toFile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Unique
|
|
||||||
private DhServerLevel dhServerLevel;
|
|
||||||
@Unique
|
|
||||||
private FakeLevelWrapper fakeLevelWrapper;
|
|
||||||
@Unique
|
|
||||||
public LocalSaveStructure saveStructure;
|
|
||||||
|
|
||||||
@Shadow @Final
|
|
||||||
private DimensionDataStorage overworldDataStorage;
|
|
||||||
@Shadow @Final
|
|
||||||
private LevelStorageSource.LevelStorageAccess levelStorage;
|
|
||||||
@Shadow @Final
|
|
||||||
private WorldGenSettings worldGenSettings;
|
|
||||||
|
|
||||||
@Inject(method = "Lnet/minecraft/util/worldupdate/WorldUpgrader;work()V",
|
|
||||||
at = @At(value = "INVOKE")
|
|
||||||
)
|
|
||||||
private void initWorldUpgrade() {
|
|
||||||
saveStructure = new LocalSaveStructure();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "Lnet/minecraft/util/worldupdate/WorldUpgrader;work()V",
|
|
||||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/util/worldupdate/WorldUpgrader;getAllChunkPos(Lnet/minecraft/resources/ResourceKey;)Ljava/util/List;", shift = At.Shift.AFTER),
|
|
||||||
locals = LocalCapture.CAPTURE_FAILSOFT
|
|
||||||
)
|
|
||||||
private void startWorldUpgrade(CallbackInfo info, ResourceKey resourceKey) {
|
|
||||||
ResourceKey<Level> key = resourceKey;
|
|
||||||
fakeLevelWrapper = new FakeLevelWrapper(levelStorage, worldGenSettings, key);
|
|
||||||
dhServerLevel = new DhServerLevel(saveStructure, fakeLevelWrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user